<!DOCTYPE html>
<!-- ###BEGIN###{EventSubscriptions} -->
<!-- ###END###{EventSubscriptions} -->
<!-- ###BEGIN###{Desktop-Settings} -->
<!-- ###END###{Desktop-Settings} -->
<!-- ###BEGIN###{Desktop-Multi} -->
<!-- ###END###{Desktop-Multi} -->
<!-- ###BEGIN###{ComputerSelectorNoImages} -->
<!-- ###END###{ComputerSelectorNoImages} -->
<!-- ###BEGIN###{ComputerSelector-Local-ScriptOnly} -->
<!-- ###END###{ComputerSelector-Local-ScriptOnly} -->
<html lang="en" style="height:100%">
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta name="format-detection" content="telephone=no">
    <link rel="icon" type="image/png" href=""> <!-- Stop favicon.ico from loading -->
<!-- ###BEGIN###{Look-Commander} -->
    <!-- ###BEGIN###{ComputerSelector} -->
    <link type="text/css" href="styles-commander-node.css" media="screen" rel="stylesheet" title="CSS" />
    <!-- ###END###{ComputerSelector} -->
    <!-- ###BEGIN###{!ComputerSelector} -->
    <link type="text/css" href="styles-commander.css" media="screen" rel="stylesheet" title="CSS" />
    <!-- ###END###{!ComputerSelector} -->
<!-- ###END###{Look-Commander} -->
<!-- ###BEGIN###{Look-Branded} -->
    <link type="text/css" href="styles-branded.css" media="screen" rel="stylesheet" title="CSS" />
<!-- ###END###{Look-Branded} -->
<!-- ###BEGIN###{Look-ISDU} -->
    <link type="text/css" href="styles-isdu.css" media="screen" rel="stylesheet" title="CSS" />
<!-- ###END###{Look-ISDU} -->
<!-- ###BEGIN###{Look-BrandedCommander} -->
    <link type="text/css" href="styles-brandedcommander.css" media="screen" rel="stylesheet" title="CSS" />
<!-- ###END###{Look-BrandedCommander} -->
<!-- ###BEGIN###{Look-Unite} -->
    <link type="text/css" href="styles-unite.css" media="screen" rel="stylesheet" title="CSS" />
<!-- ###END###{Look-Unite} -->
<!-- ###BEGIN###{Look-MeshCentral} -->
    <link type="text/css" href="styles-mesh.css" media="screen" rel="stylesheet" title="CSS" />
<!-- ###END###{Look-MeshCentral} -->
    <script type="text/javascript" src="common-0.0.1.js"></script>
<!-- ###BEGIN###{Mode-LMS} -->
    <script type="text/javascript" src="amt-lms-0.0.1.js"></script>
    <script type="text/javascript" src="amt-wsman-ws-0.2.0.js"></script>
<!-- ###END###{Mode-LMS} -->
<!-- ###BEGIN###{Mode-NodeWebkit} -->
    <script type="text/javascript" src="amt-wsman-node-0.2.0.js"></script>
    <script type="text/javascript" src="amt-redir-node-0.1.0.js"></script>
    <script type="text/javascript" src="amt-scanner-0.1.0.js"></script>
<!-- ###END###{Mode-NodeWebkit} -->
<!-- ###BEGIN###{Mode-WebSite} -->
    <script type="text/javascript" src="amt-wsman-ws-0.2.0.js"></script>
    <script type="text/javascript" src="amt-redir-ws-0.1.0.js"></script>
<!-- ###END###{Mode-WebSite} -->
<!-- ###BEGIN###{Mode-Firmware} -->
    <script type="text/javascript" src="amt-wsman-ajax-0.2.0.js"></script>
    <script type="text/javascript" src="amt-redir-ws-0.1.0.js"></script>
<!-- ###END###{Mode-Firmware} -->
<!-- ###BEGIN###{IDER} -->
    <script type="text/javascript" src="amt-ider-ws-0.0.1.js"></script>
    <!-- ###BEGIN###{IDER-IMRSDK} -->
    <script type="text/javascript" src="amt-ider-node-0.0.1.js"></script>
    <!-- ###END###{IDER-IMRSDK} -->
    <!-- ###BEGIN###{Mode-MeshCentral2} -->
    <script type="text/javascript" src="amt-ider-server-ws-0.0.1.js"></script>
    <!-- ###END###{Mode-MeshCentral2} -->
<!-- ###END###{IDER} -->
<!-- ###BEGIN###{Mode-MeshCentral2} -->
    <script type="text/javascript" src="amt-wsman-ws-0.2.0.js"></script>
    <script type="text/javascript" src="amt-redir-ws-0.1.0.js"></script>
<!-- ###END###{Mode-MeshCentral2} -->
    <script type="text/javascript" src="amt-wsman-0.2.0.js"></script>
    <script type="text/javascript" src="amt-0.2.0.js"></script>
<!-- ###BEGIN###{Certificates} -->
    <script type="text/javascript" src="forge.js/forge.bundle.js"></script>
    <script type="text/javascript" src="amt-certificates-0.0.1.js"></script>
<!-- ###END###{Certificates} -->
<!-- ###BEGIN###{Scripting} -->
    <script type="text/javascript" src="amt-script-0.2.0.js"></script>
<!-- ###END###{Scripting} -->
<!-- ###BEGIN###{Desktop} -->
    <script type="text/javascript" src="amt-desktop-0.0.2.js"></script>
    <style type="text/css">
        .rb { cursor: pointer; border: none; float: right; font-size: 130%; margin-right: 4px; }
    </style>
<!-- ###END###{Desktop} -->
<!-- ###BEGIN###{DesktopInband} -->
    <script type="text/javascript" src="agent-desktop-0.0.2.js"></script>
    <script type="text/javascript" src="agent-redir-rtc-0.1.0.js"></script>
<!-- ###END###{DesktopInband} -->
<!-- ###BEGIN###{Terminal} -->
    <script type="text/javascript" src="amt-terminal-0.0.2.js"></script>
<!-- ###END###{Terminal} -->
<!-- ###BEGIN###{PowerControl-Advanced} -->
<!-- ###BEGIN###{PowerControl-OneClick} -->
    <script type="text/javascript" src="webserver-0.0.1.js"></script>
<!-- ###END###{PowerControl-Advanced} -->
<!-- ###END###{PowerControl-OneClick} -->
<!-- ###BEGIN###{Inflate} -->
    <script type="text/javascript" src="zlib.js"></script>
    <script type="text/javascript" src="zlib-inflate.js"></script>
    <script type="text/javascript" src="zlib-adler32.js"></script>
    <script type="text/javascript" src="zlib-crc32.js"></script>
<!-- ###END###{Inflate} -->
<!-- ###BEGIN###{USBSetup} -->
    <script type="text/javascript" src="amt-setupbin-0.1.0.js"></script>
<!-- ###END###{USBSetup} -->
<!-- ###BEGIN###{FileSaver} -->
    <script type="text/javascript" src="filesaver.1.1.20151003.js"></script>
<!-- ###END###{FileSaver} -->
<!-- ###BEGIN###{MeshServerConnect} -->
    <script type="text/javascript" src="meshcentral-server-0.2.0.js"></script>
    <script type="text/javascript" src="websocket-wrapper-0.2.0.js"></script>
<!-- ###END###{MeshServerConnect} -->
<!-- ###BEGIN###{Mode-LMS} -->
    <style type="text/css">
        .menuitem { cursor: pointer; border: none; padding:5px; }
        .menuitem:hover { background-color: #6b9dc7; }
    </style>
<!-- ###END###{Mode-LMS} -->
<!-- ###BEGIN###{ComputerSelector} -->
    <style type="text/css">
        .menuitem { cursor: pointer; border: none; padding:5px; }
        .menuitem:hover { background-color: #6b9dc7; }
    </style>
<!-- ###END###{ComputerSelector} -->
<!-- ###BEGIN###{ContextMenus} -->
    <style>
        .contextMenu {
            background: #F9F9F9;
            box-shadow: 0 0 12px rgba( 0, 0, 0, .3 );
            border: 1px solid #ccc;
            /*border-radius: 4px;*/
            position: absolute;
            top: 0;
            left: 0;
            list-style: none;
            margin: 0;
            padding: 5px;
            min-width: 100px;
            max-width: 150px;
            z-index: 500;
        }

        .cmtext {
            color: #444;
            display: inline-block;
            padding-left: 8px;
            padding-right: 8px;
            padding-top: 5px;
            padding-bottom: 5px;
            text-decoration: none;
            width: 85%;
            cursor: default;
            overflow: hidden;
            position: relative;
        }

            .cmtext:hover {
                color: #f9f9f9;
                background: #999;
            }
    </style>
<!-- ###END###{ContextMenus} -->
<!-- ###BEGIN###{DesktopInbandFiles} -->
    <style>
        .fileIcon1 {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            float: left;
            margin-top: 1px;
        }

        .fileIcon2 {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            float: left;
            margin-top: 1px;
        }

        .fileIcon3 {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            float: left;
            margin-top: 1px;
        }

        .filelist {
            -moz-user-select: none;
            -khtml-user-select: none;
            -webkit-user-select: none;
            -o-user-select: none;
            cursor: default;
            -khtml-user-drag: element;
            background-color: white;
            clear: both;
        }

        .fsize {
            float: right;
            text-align: right;
            width: 180px;
        }
    </style>
<!-- ###END###{DesktopInbandFiles} -->
<!-- ###BEGIN###{SessionRecording} -->
    <style>
        .cameraIcon {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            margin-top:2px;
            margin-right:4px;
            cursor:pointer;
            float:right;
        }

        .videoIcon {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            margin-top:2px;
            margin-right:4px;
            cursor:pointer;
            float:right;
        }

        .videoIconRed {
            background: url();
            height: 16px;
            width: 16px;
            cursor: pointer;
            border: none;
            margin-top:2px;
            margin-right:4px;
            cursor:pointer;
            float:right;
        }
    </style>
<!-- ###END###{SessionRecording} -->
<!-- ###BEGIN###{Look-Commander} -->
    <!-- ###BEGIN###{!ComputerSelector-Local-ScriptOnly} -->
    <!-- ###BEGIN###{!Mode-LMS} -->
    <title>MeshCommander</title>
    <!-- ###END###{!Mode-LMS} -->
    <!-- ###BEGIN###{Mode-LMS} -->
    <title>LMS MeshCommander</title>
    <!-- ###END###{Mode-LMS} -->
    <!-- ###END###{!ComputerSelector-Local-ScriptOnly} -->
    <!-- ###BEGIN###{ComputerSelector-Local-ScriptOnly} -->
    <title>ScriptCommander</title>
    <!-- ###END###{ComputerSelector-Local-ScriptOnly} -->
<!-- ###END###{Look-Commander} -->
<!-- ###BEGIN###{Look-Branded} -->
    <title>Intel&reg; Active Management Technology</title>
<!-- ###END###{Look-Branded} -->
<!-- ###BEGIN###{Look-ISDU} -->
    <title>Intel&reg; System Defense Utility</title>
<!-- ###END###{Look-ISDU} -->
<!-- ###BEGIN###{Look-BrandedCommander} -->
    <title>Intel&reg; Manageability Commander</title>
<!-- ###END###{Look-BrandedCommander} -->
<!-- ###BEGIN###{Look-Unite} -->
    <title>Intel&reg; Unite - Hardware Management</title>
<!-- ###END###{Look-Unite} -->
</head>
<!-- ###BEGIN###{!ContextMenus} -->
<body onunload=cleanup()>
<!-- ###END###{!ContextMenus} -->
<!-- ###BEGIN###{ContextMenus} -->
<body onunload=cleanup() oncontextmenu=handleContextMenu(event)>
<!-- ###END###{ContextMenus} -->
    <div id=id_topheader class=header>
        <!-- ###BEGIN###{!Look-MeshCentral} -->
        <!-- ###BEGIN###{Look-Unite} -->
        <table style=width:100%;height:55px>
            <tr>
                <td valign=top nowrap="nowrap">
                    <p class="top1">Intel<sup style="font-size:10px">&reg;</sup>&nbsp;Active Management Technology</p>
                    <p class="top2" id="id_computername"></p>
                </td>
                <td valign="top">
                    <img width="165" height="42" align="right" style="border:0;margin-top:10px;margin-right:12px" src="images-unite/title.png" />
                </td>
            </tr>
        </table>
        <!-- ###END###{Look-Unite} -->
        <!-- ###BEGIN###{Look-ISDU} -->
        <div>
            <div style="background-image:url(images-isdu/LogoWhite42.png);width:63px;height:42px;float:right;margin-top:14px;margin-right:20px;padding:0"></div>
            <div style="width:425px;height:69px"><div style="background-image:url(images-isdu/ISDUTitle.png);position:relative;top:26px;left:20px;width:282px;height:20px"></div></div>
            <p id="id_computername" style="display:none"></p>
        </div>
        <!-- ###END###{Look-ISDU} -->
        <!-- ###BEGIN###{Look-BrandedCommander} -->
        <!-- ###BEGIN###{Mode-NodeWebkit} -->
        <div>
            <div style="background-image:url(images-brandedcommander/LogoWhite42.png);width:63px;height:42px;float:right;margin-top:14px;margin-right:20px;padding:0"></div>
            <div style="width:425px;height:69px"><div style="background-image:url(images-brandedcommander/CommanderTitle.png);position:relative;top:21px;left:20px;width:443px;height:33px"></div></div>
            <p id="id_computername" style="display:none"></p>
        </div>
        <!-- ###END###{Mode-NodeWebkit} -->
        <!-- ###BEGIN###{!Mode-NodeWebkit} -->
        <table style="width:100%;height:55px">
            <tr>
                <td valign=top nowrap="nowrap">
                    <p class="top1">Intel<sup style="font-size:10px">&reg;</sup>&nbsp;Manageability Commander</p>
                    <p class="top2" id="id_computername"></p>
                </td>
                <td valign="top">
                    <img width="73" height="53" align="right" style="border:0" src="images-branded/logo.gif" />
                </td>
            </tr>
        </table>
        <!-- ###END###{!Mode-NodeWebkit} -->
        <!-- ###END###{Look-BrandedCommander} -->
        <!-- ###BEGIN###{!Look-ISDU} -->
        <!-- ###BEGIN###{!Look-BrandedCommander} -->
        <table class="topCell" style="width:100%;height:55px">
            <tr>
                <td valign=top nowrap="nowrap">
                    <!-- ###BEGIN###{Look-Commander} -->
                    <!-- ###BEGIN###{Switchbox} -->
                    <p class="top1">Manageability Switchbox</p>
                    <!-- ###END###{Switchbox} -->
                    <!-- ###BEGIN###{!Switchbox} -->
                    <!-- ###BEGIN###{!ComputerSelector-Local-ScriptOnly} -->

                    <!-- ###BEGIN###{!Mode-LMS} -->
                    <p class="top1">MeshCommander</p>
                    <!-- ###END###{!Mode-LMS} -->
                    <!-- ###BEGIN###{Mode-LMS} -->
                    <p class="top1">LMS MeshCommander</p>
                    <!-- ###END###{Mode-LMS} -->
                    <!-- ###END###{!ComputerSelector-Local-ScriptOnly} -->
                    <!-- ###BEGIN###{ComputerSelector-Local-ScriptOnly} -->
                    <p class="top1">ScriptCommander</p>
                    <!-- ###END###{ComputerSelector-Local-ScriptOnly} -->
                    <!-- ###END###{!Switchbox} -->
                    <!-- ###END###{Look-Commander} -->
                    <!-- ###BEGIN###{Look-Intel-AMT} -->
                    <p class="top1">Intel<sup style="font-size:10px">&reg;</sup>&nbsp;Active Management Technology</p>
                    <!-- ###END###{Look-Intel-AMT} -->
                    <!-- ###BEGIN###{Look-Intel-SM} -->
                    <p class="top1">Intel<sup style="font-size:10px">&reg;</sup>&nbsp;Standard Manageability</p>
                    <!-- ###END###{Look-Intel-SM} -->
                    <!-- ###BEGIN###{Look-Intel-SBT} -->
                    <p class="top1">Intel<sup style="font-size:10px">&reg;</sup>&nbsp;Small Buisness Technology</p>
                    <!-- ###END###{Look-Intel-SBT} -->
                    <p class="top2" id="id_computername"></p>
                </td>
                <td valign="top">
                    <!-- ###BEGIN###{!Mode-LMS} -->
                    <!-- ###BEGIN###{!Mode-Firmware} -->
                    <!-- ###BEGIN###{Look-Commander} -->
                    <img width="166" height="64" align="right" style="border:0" src="images-commander/logo.png" />
                    <!-- ###END###{Look-Commander} -->
                    <!-- ###END###{!Mode-Firmware} -->
                    <!-- ###END###{!Mode-LMS} -->
                    <!-- ###BEGIN###{Look-Branded} -->
                    <img width="73" height="53" align="right" style="border:0" src="images-branded/logo.gif" />
                    <!-- ###END###{Look-Branded} -->
                </td>
            </tr>
        </table>
        <!-- ###END###{!Look-BrandedCommander} -->
        <!-- ###END###{!Look-ISDU} -->
        <!-- ###END###{!Look-MeshCentral} -->
        <!-- ###BEGIN###{Mode-MeshCentral2} -->
        <table id="id_KVMTable" cellpadding="0" cellspacing="0" style="width: 100%; padding: 0px; padding: 0px; margin-top: 0px">
            <tr>
                <td id="id_normalScreenToolbar" class="style6">
                    <div>
                        &nbsp;<input type="button" class="connectbutton" id="xconnectbutton1" value="Connect" onclick="connectButtonfunction(event, false)" onkeypress="return false" onkeydown="return false">
                        &nbsp;<span id="constatus"></span>
                    </div>
                </td>
            </tr>
        </table>
        <!-- ###END###{Mode-MeshCentral2} -->
        <div class="progressbar">
            <!-- ###BEGIN###{Look-MeshCentral} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:red"></div>
            <!-- ###END###{Look-MeshCentral} -->
            <!-- ###BEGIN###{Look-Commander} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:red"></div>
            <!-- ###END###{Look-Commander} -->
            <!-- ###BEGIN###{Look-Branded} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:orange"></div>
            <!-- ###END###{Look-Branded} -->
            <!-- ###BEGIN###{Look-ISDU} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:red"></div>
            <!-- ###END###{Look-ISDU} -->
            <!-- ###BEGIN###{Look-BrandedCommander} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:red"></div>
            <!-- ###END###{Look-BrandedCommander} -->
            <!-- ###BEGIN###{Look-Unite} -->
            <div id="id_progressbar" style="height:2px;width:0%;background-color:red"></div>
            <!-- ###END###{Look-Unite} -->
        </div>
    </div>
    <div id="id_messageview" class="fullcell" style="text-align:center;padding-top:100px;font-size:20px">
        <!-- ###BEGIN###{Look-MeshCentral} -->
        <span id="id_messageviewstr">Disconnected</span>
        <!-- ###END###{Look-MeshCentral} -->
        <!-- ###BEGIN###{!Look-MeshCentral} -->
        <span id="id_messageviewstr">Loading...</span>
        <!-- ###END###{!Look-MeshCentral} -->
        <!-- ###BEGIN###{ComputerSelector} -->
        <br><br><input id="id_messageviewbutton" type=button value=Close onclick=disconnect()>
        <!-- ###END###{ComputerSelector} -->
        <!-- ###BEGIN###{Mode-LMS} -->
        <br><br><input type=button value=Close onclick=disconnect()>
        <!-- ###END###{Mode-LMS} -->
    </div>
    <!-- ###BEGIN###{Mode-LMS} -->
    <div id="id_lmsMainPanel" class="fullcell" style="display:none">
        <div style="background-color:lightgray;height:24px;margin-bottom:6px;padding-top:2px">
            <div id="id_lmsToolBarContent" style="display:none">
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <div style="float:left;height:26px;width:26px;cursor:pointer" onclick="toolmenuclick(0)">
                    <span style="font-size:16px">&nbsp;&#9776;</span>
                </div>
                <!-- ###END###{!Mode-NodeWebkit} -->
                <div>
                    <input type="button" value="Refresh" onclick="lmsRefresh()">
                    <input id="id_lmsActivateButton" type="button" value="Activate..." style="display:none" onclick="lmsActivate()">
                    <input id="id_lmsDeactivateButton" type="button" value="Deactivate..." style="display:none" onclick="lmsDeactivate()">
                    <input id="id_lmsLoginButton" type="button" value="Login..." style="display:none" onclick="lmsLogin()">
                    <input id="id_lmsConfigureButton" type="button" value="Intel&reg; AMT Login..." style="display:none" onclick="lmsConfigure()">
                </div>
            </div>
        </div>
        <div id="id_lmsData" style="margin:10px"></div>
        <div id="id_lmsData2" style="margin:10px"></div>
    </div>
    <!-- ###END###{Mode-LMS} -->
    <!-- ###BEGIN###{PowerControl-OneClick} -->
    <div id=TransferNotification style="display:none;background-color:lightgrey;position:absolute;left:10px;bottom:10px;border-radius:5px;padding:4px;z-index:1000;box-shadow:0px 0px 10px #333"></div>
    <!-- ###END###{PowerControl-OneClick} -->
    <!-- ###BEGIN###{Mode-NodeWebkit} -->
    <div id=LeftSideToolBar style="position:absolute;left:0px;bottom:0px;width:52px;top:69px;background:#113962;background:linear-gradient(to bottom, #104893 0%,#113962 100%);color:white;display:none">
        <div style="height:23px"></div>
        <div id=LeftMenuMyDevices class="lbbutton lbbuttonsel2" title="Computer Management" onclick=go(101)>
            <div class="lb1" style="position:absolute;top:6px;left:6px"></div>
        </div>
        <div id=LeftMenuMyCerts class="lbbutton" title="Certificate Manager" onclick=go(103)>
            <div class="lb2" style="position:absolute;top:6px;left:6px"></div>
        </div>
        <div id=LeftMenuMyUsb class="lbbutton" title="Setup.bin Manager" onclick=go(102)>
            <div class="lb3" style="position:absolute;top:6px;left:6px"></div>
        </div>
        <!-- ###BEGIN###{SessionRecording} -->
        <div id=LeftMenuPlayer class="lbbutton" title="Session Player" onclick=go(104)>
            <div class="lb4" style="position:absolute;top:6px;left:6px"></div>
        </div>
        <!-- ###END###{SessionRecording} -->
    </div>
    <!-- ###END###{Mode-NodeWebkit} -->
    <!-- ###BEGIN###{ComputerSelector} -->
    <div id="id_computerSelector" class="fullcell" style="display:none">
        <!-- ###BEGIN###{Mode-NodeWebkit} -->
        <div id=UpdateNotification style="display:none;background-color:lightgrey;position:absolute;left:10px;bottom:10px;border-radius:5px;padding:10px;z-index:1000;box-shadow: 0px 0px 20px #888888">
            <a style="cursor:pointer;color:blue" onclick="NW_PerformUpdate()"><u id="UpdateNotificationText"></u></a> &nbsp; <span onclick="NW_HideUpdateNotification()" style="cursor:pointer;font-size:15px">&#x2716;</span>
        </div>
        <!-- ###END###{Mode-NodeWebkit} -->
        <!-- ###BEGIN###{ComputerSelectorToolbar} -->
        <table style="background-color:#808080;width:100%">
            <tr>
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <td id=toolmenuicondiv style="width:26px;cursor:pointer" onclick="toolmenuclick(0)">
                    <span style="font-size:16px">&nbsp;&#9776;</span>
                </td>
                <!-- ###END###{!Mode-NodeWebkit} -->
                <!-- ###BEGIN###{MeshServerConnect} -->
                <td id="idx_disconnectMeshCentralButton" style="display:none">
                    <input type="button" value="Disconnect" onclick="meshCentralDisconnect()">
                </td>
                <!-- ###END###{MeshServerConnect} -->
                <td>
                    <span id="id_noScriptButtons">
                        <!-- ###BEGIN###{ComputerSelector-Remote} -->
                        <input type="button" value="Refresh" onclick="loadServerComputerList()">
                        <!-- ###END###{ComputerSelector-Remote} -->
                        <!-- ###BEGIN###{ComputerSelector-Local} -->
                        <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                        <input type="button" value="New..." onclick="newComputerList()">
                        <input type="button" value="Open..." onclick="openComputerList()">
                        <!-- ###BEGIN###{FileSaver} -->
                        <input id="saveComputersButton" type="button" value="Save..." onclick="saveComputerList()">
                        <!-- ###END###{FileSaver} -->
                        <!-- ###END###{!Mode-NodeWebkit} -->
                        <input type="button" value="Add Computer..." onclick="addComputer()">
                        <!-- ###END###{ComputerSelector-Local} -->
                        <!-- ###BEGIN###{ComputerSelectorScanner} -->
                        <!-- ###BEGIN###{Mode-NodeWebkit} -->
                        <input type="button" value="Scan..." onclick="showScanDialog()">
                        <!-- ###END###{Mode-NodeWebkit} -->
                        <!-- ###END###{ComputerSelectorScanner} -->
                    </span>
                    <!-- ###BEGIN###{Scripting} -->
                    <!-- ###BEGIN###{!Look-BrandedCommander} -->
                    <input id="idx_runScriptOnComputersButton" type="button" value="Run Script..." onclick="mscript_runScriptDlg()">
                    <!-- ###END###{!Look-BrandedCommander} -->
                    <!-- ###BEGIN###{Look-BrandedCommander} -->
                    <input id="idx_runScriptOnComputersButton" type="button" value="Run Script..." onclick="mscript_runScriptDlg()" style="display:none">
                    <!-- ###END###{Look-BrandedCommander} -->
                    <!-- ###END###{Scripting} -->
                </td>
                <td style="text-align:right">
                    <!-- ###BEGIN###{!Look-BrandedCommander} -->
                    <input id="computerFilter" placeholder="Filter" onkeyup="computerFilterFunc()" autocomplete=off onfocus=onFilterFocus(true) onblur=onFilterFocus(false)>
                    <!-- ###END###{!Look-BrandedCommander} -->
                </td>
            </tr>
        </table>
        <!-- ###BEGIN###{ComputerSelector-Local} -->
        <div id="id_computerListParent" style="position:fixed;top:96px;left:0;right:300px;bottom:0;overflow-y:scroll" cm="Add&nbsp;Computer...#addComputer()">
        <!-- ###END###{ComputerSelector-Local} -->
        <!-- ###BEGIN###{!ComputerSelector-Local} -->
            <div id="id_computerListParent" style="position:fixed;top:96px;left:0;right:300px;bottom:0;overflow-y:scroll">
        <!-- ###END###{!ComputerSelector-Local} -->
                <div id="id_noKnownComputers" style="text-align:center;margin-top:36px;color:gray">
                    <span style="font-size:20px">No known computers</span>
                    <!-- ###BEGIN###{ComputerSelector-Local} -->
                    <div style="margin:4px">Get started by <a onclick="addComputer()" style="cursor:pointer"><u>adding</u></a> computers or drag & dropping<br>a computer list file in this window.</div>
                    <!-- ###END###{ComputerSelector-Local} -->
                </div>
                <div id="id_computerList" style="font-size:20px"></div>
            </div>
        <div id="id_computerDetailsParent" style="position:fixed;top:96px;width:300px;right:0;bottom:0">
            <div id="id_computerDetails" style="font-size:16px;margin:4px"></div>
        </div>
        <!-- ###END###{ComputerSelectorToolbar} -->
        <!-- ###BEGIN###{!ComputerSelectorToolbar} -->
        <div id="id_computerListParent" style="position:fixed;top:69px;left:0;right:300px;bottom:0;overflow-y:scroll" cm="Add&nbsp;Computer...#addComputer()">
            <div id="id_noKnownComputers" style="text-align:center;margin-top:36px;color:gray">
                <span style="font-size:20px">No known computers</span>
                <!-- ###BEGIN###{ComputerSelector-Local} -->
                <div style="margin:4px">Get started by <a onclick="addComputer()" style="cursor:pointer"><u>adding</u></a> computers or drag & dropping<br>a computer list file in this window.</div>
                <!-- ###END###{ComputerSelector-Local} -->
            </div>
            <div id="id_computerList" style="font-size:20px"></div>
        </div>
        <div id="id_computerDetailsParent" style="position:fixed;top:69px;width:300px;right:0;bottom:0;background-color:white">
            <div id="id_computerDetails" style="font-size:16px;margin:8px"></div>
        </div>
        <!-- ###END###{!ComputerSelectorToolbar} -->
    </div>
    <div id="id_computerSelectorMenu" style="background-color:#EEEEEE;display:none;position:absolute;left:0;top:94px;width:200px;padding:3px;z-index:1000;box-shadow:5px 5px 5px #888888;border:1px solid gray">
        <div class="menuitem" onclick="toolmenuclick(101)"><span id="id_menuitem1">&bull; </span>Computer Management</div>
        <!-- ###BEGIN###{CertificateManager} -->
        <div class="menuitem" onclick="toolmenuclick(103)"><span id="id_menuitem3" style="display:none">&bull; </span>Certificate Manager</div>
        <!-- ###END###{CertificateManager} -->
        <!-- ###BEGIN###{USBSetup} -->
        <div class="menuitem" onclick="toolmenuclick(102)"><span id="id_menuitem2" style="display:none">&bull; </span>USB Setup.bin Editor</div>
        <!-- ###END###{USBSetup} -->
        <!-- ###BEGIN###{SessionRecording} -->
        <div class="menuitem" onclick="toolmenuclick(104)"><span id="id_menuitem4" style="display:none">&bull; </span>Session Player</div>
        <!-- ###END###{SessionRecording} -->
    </div>
    <!-- ###END###{ComputerSelector} -->
    <!-- ###BEGIN###{Mode-LMS} -->
    <div id="id_computerSelectorMenu" style="background-color:#EEEEEE;display:none;position:absolute;left:0;top:94px;width:200px;padding:3px;z-index:1000;box-shadow:5px 5px 5px #888888;border:1px solid gray">
        <div class="menuitem" onclick="toolmenuclick(101)"><span id="id_menuitem1">&bull; </span>Computer Configuration</div>
        <!-- ###BEGIN###{USBSetup} -->
        <div class="menuitem" onclick="toolmenuclick(102)"><span id="id_menuitem2" style="display:none">&bull; </span>USB Setup.bin Editor</div>
        <!-- ###END###{USBSetup} -->
    </div>
    <!-- ###END###{Mode-LMS} -->
    <!-- ###BEGIN###{USBSetup} -->
    <div id="id_usbSetupPanel" class="fullcell" style="display:none">
        <!-- ###BEGIN###{ComputerSelectorToolbar} -->
        <table style="background-color:#808080;width:100%">
            <tr>
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <td style="width:26px;cursor:pointer" onclick="toolmenuclick(0)">
                    <span style="font-size:16px">&nbsp;&#9776;</span>
                </td>
                <!-- ###END###{!Mode-NodeWebkit} -->
                <td>
                    <input type="button" value="New..." onclick="usb_newSetupBin()">
                    <input type="button" value="Open..." onclick="usb_openSetupBin()">
                    <!-- ###BEGIN###{FileSaver} -->
                    <input id="id_saveSetupBin" type="button" value="Save..." onclick="usb_saveSetupBin()">
                    <!-- ###END###{FileSaver} -->
                </td>
            </tr>
        </table>
        <div id="id_usbSetupPanel2" style="position:fixed;overflow-y:scroll;left:0;right:0;bottom:0;top:96px">
            <div id="id_StartupScreen" style="width:100%;text-align:center;color:gray;margin-top:36px">
                <span style="font-size:20px">Intel<sup style="font-size:10px">&reg;</sup> AMT USB Setup.bin Manager</span>
                <div style="margin:4px">Get started by <a onclick="usb_newSetupBin()" style="cursor:pointer"><u>creating</u></a> a new file, <a onclick="usb_openSetupBin()" style="cursor:pointer"><u>opening</u></a> an existing one<br>or drag & dropping a setup.bin file in this window.</div>
            </div>
            <div id="id_SetupBinArea" style="margin:10px"></div>
        </div>
        <!-- ###END###{ComputerSelectorToolbar} -->
        <!-- ###BEGIN###{!ComputerSelectorToolbar} -->
        <div style="position:fixed;overflow-y:scroll;left:0;right:0;bottom:0;top:69px">
            <div id="id_StartupScreen" style="width:100%;text-align:center;color:gray;margin-top:36px">
                <span style="font-size:20px">Intel<sup style="font-size:10px">&reg;</sup> AMT USB Setup.bin Manager</span>
                <div style="margin:4px">Get started by <a onclick="usb_newSetupBin()" style="cursor:pointer"><u>creating</u></a> a new file, <a onclick="usb_openSetupBin()" style="cursor:pointer"><u>opening</u></a> an existing one<br>or drag & dropping a setup.bin file in this window.</div>
            </div>
            <div id="id_SetupBinArea" style="margin:10px"></div>
        </div>
        <!-- ###END###{!ComputerSelectorToolbar} -->
    </div>
    <!-- ###END###{USBSetup} -->
    <!-- ###BEGIN###{CertificateManager} -->
    <div id="id_certManagerPanel" class="fullcell" style="display:none">
        <!-- ###BEGIN###{ComputerSelectorToolbar} -->
        <table style="background-color:#808080;width:100%">
            <tr>
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <td style="width:26px;cursor:pointer" onclick="toolmenuclick(0)">
                    <span style="font-size:16px">&nbsp;&#9776;</span>
                </td>
                <!-- ###END###{!Mode-NodeWebkit} -->
                <td>
                    <input type="button" value="Create Root Certificate..." onclick="cert_createNew()">
                    <input id="IssueCertButton" type="button" value="Issue Certificate..." onclick="cert_issueNew()">
                    <input type="button" value="Import Certificate..." onclick="cert_importCert()">
                </td>
            </tr>
        </table>
        <div id="id_certManagerPanel2" style="position:fixed;overflow-y:scroll;left:0;right:0;bottom:0;top:96px">
            <div id="id_certStartScreen" style="width:100%;text-align:center;color:gray;margin-top:36px">
                <span style="font-size:20px">Certificate Manager</span>
                <div style="margin:4px">Certificates play an important role in all sorts of Intel&reg; AMT security tasks: TLS network authentication,<br />CIRA configuration, audit log signing and more. Use this panel to create and manage your console certificate.</div>
            </div>
            <div id="id_certManagerMainArea" style="font-size:20px"></div>
            <!-- ###BEGIN###{Mode-NodeWebkit} -->
            <input id="certOpenFile" type="file" style="display:none" accept=".cer;*.pfx;*.p12;*.pem;*.crt">
            <!-- ###END###{Mode-NodeWebkit} -->
        </div>
        <!-- ###END###{ComputerSelectorToolbar} -->
        <!-- ###BEGIN###{!ComputerSelectorToolbar} -->
        <div style="position:fixed;overflow-y:scroll;left:0;right:0;bottom:0;top:95px">
            <div id="id_certStartScreen" style="width:100%;text-align:center;color:gray;margin-top:36px">
                <span style="font-size:20px">Certificate Manager</span>
                <div style="margin:4px">Certificates play an important role in all sorts of Intel&reg; AMT security tasks: TLS network authentication,<br />CIRA configuration, audit log signing and more. Use this panel to create and manage your console certificate.</div>
            </div>
            <div id="id_certManagerMainArea" style="margin:10px"></div>
        </div>
        <!-- ###END###{!ComputerSelectorToolbar} -->
    </div>
    <!-- ###END###{CertificateManager} -->
    <!-- ###BEGIN###{SessionRecording} -->
    <div id="id_sessionPlayerPanel" class="fullcell" style="display:none">
        <table style="background-color:#808080;width:100%">
            <tr>
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <td style="width:26px;cursor:pointer" onclick="toolmenuclick(0)">
                    <span style="font-size:16px">&nbsp;&#9776;</span>
                </td>
                <!-- ###END###{!Mode-NodeWebkit} -->
                <td>
                    <div style="float:right">
                        <input id="srec_toggleviewmode" type="button" value="Toggle View Mode" style="display:none" onclick="srec_toggleAspectRatio(1)">
                    </div>
                    <input type="button" id="srec_OpenFileButton" value="Open File..." onclick="srec_openfile()">
                    <span id="srec_deskstatus" style="margin-left:4px"></span>
                </td>
            </tr>
        </table>
        <div style="overflow:hidden">
            <div id=srec_deskarea0>
                <div id=srec_deskarea2 style="height:2px">
                    <div style="background-color:gray"><div id="srec_progressbar" style="height:2px;width:0%;background-color:red"></div></div>
                </div>
                <div id=srec_deskarea3x style="position:relative;max-height:calc(100vh - 123px);height:calc(100vh - 123px)" onclick="srec_togglePause()">
                    <div id="srec_metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
                    <div id=srec_DeskParent style="width:100%;height:100%;background-color:black;display:none">
                        <canvas id=srec_Desk width=640 height=480></canvas>
                    </div>
                    <div id=srec_TermParent style="position:absolute;top:0;height:100%;width:100%;background-color:black;display:none">
                        <div><pre id=srec_Term></pre></div>
                    </div>
                    <!--<div id=srec_p11DeskConsoleMsg style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick=clearConsoleMsg()></div>-->
                </div>
                <div id=srec_deskarea4 style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
                    <div style="float:right;text-align:right;padding-right:4px">
                        <div id="srec_timespan" style="padding-top:4px;padding-right:4px">00:00:00</div>
                    </div>
                    <div>
                        &nbsp;
                        <input id="srec_PlayButton" type=button value="Play" disabled="disabled" onclick="srec_play()">
                        <input id="srec_PauseButton" type=button value="Pause" disabled="disabled" onclick="srec_pause()">
                        <input id="srec_RestartButton" type=button value="Restart" disabled="disabled" onclick="srec_restart()">
                        <select id="srec_PlaySpeed" onchange="this.blur();">
                            <option value=4>1/4 Speed</option>
                            <option value=2>1/2 Speed</option>
                            <option value=1 selected>Normal Speed</option>
                            <option value=0.5>2x Speed</option>
                            <option value=0.25>4x Speed</option>
                            <option value=0.1>10x Speed</option>
                        </select>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- ###END###{SessionRecording} -->
    <div id="id_mainview" style="height:100%;display:none">
        <div id="id_leftbar" class=navbar>
            <!-- ###BEGIN###{Mode-NodeWebkit} -->
            <div id="tlsNotification1" style="text-align:center;padding-top:8px;color:darkblue;cursor:pointer;display:none" onclick="showTlsCert(1)"><img src="images/lock.gif" /> TLS Secured</div>
            <div id="tlsNotification2" style="text-align:center;padding-top:8px;color:darkblue;cursor:pointer;display:none" onclick="showTlsCert(1)"><img src="images/lock.gif" /> TLS Secured (Pinned)</div>
            <div id="tlsNotification3" style="text-align:center;padding-top:8px;color:darkblue;cursor:pointer;display:none" onclick="showTlsCert(1)"><img src="images/lock.gif" /> TLS (Untrusted)</div>
            <div id="tlsNotification4" style="text-align:center;padding-top:8px;color:darkblue;cursor:pointer;display:none;color:red" onclick="switchToTls()"><img src="images/unlock.gif" /> Switch to TLS</div>
            <!-- ###END###{Mode-NodeWebkit} -->
            <!-- ###BEGIN###{ComputerSelector} -->
            <div style='padding:8px'>
                <input type=button id=disconnectButton value="Disconnect" onkeypress="return false" onkeydown="return false" onclick="disconnect()" style="width:138px">
            </div>
            <!-- ###END###{ComputerSelector} -->
            <!-- ###BEGIN###{Mode-LMS} -->
            <div style='padding:8px'>
                <input type=button id=disconnectButton value="Disconnect" onkeypress="return false" onkeydown="return false" onclick="disconnect()" style="width:138px">
            </div>
            <!-- ###END###{Mode-LMS} -->
            <!-- ###BEGIN###{Mode-Firmware} -->
            <br>
            <!-- ###END###{Mode-Firmware} -->
            <!-- ###BEGIN###{Mode-MeshCentral2} -->
            <br>
            <!-- ###END###{Mode-MeshCentral2} -->
            <p id="go1" class=nav1 onclick="go(1)"><a>System Status</a></p>
            <!-- ###BEGIN###{Desktop} -->
            <p id="go14" class=nav1 onclick="go(14)"><a>Remote Desktop</a></p>
            <!-- ###BEGIN###{DesktopInbandFiles} -->
            <p id="go24" class=nav1 onclick="go(24)">&nbsp;&nbsp;<a>Files</a></p>
            <!-- ###END###{DesktopInbandFiles} -->
            <!-- ###END###{Desktop} -->
            <!-- ###BEGIN###{Terminal} -->
            <p id="go13" class=nav1 onclick="go(13)"><a>Serial-over-LAN</a></p>
            <!-- ###END###{Terminal} -->
            <!-- ###BEGIN###{HardwareInfo} -->
            <p id="go2" class=nav1 onclick="go(2)"><a>Hardware Information</a></p>
            <!-- ###END###{HardwareInfo} -->
            <!-- ###BEGIN###{EventLog} -->
            <p id="go6" class=nav1 onclick="go(6)"><a>Event Log</a></p>
            <!-- ###END###{EventLog} -->
            <!-- ###BEGIN###{AuditLog} -->
            <p id="go15" class=nav1 onclick="go(15)"><a>Audit Log</a></p>
            <!-- ###END###{AuditLog} -->
            <!-- ###BEGIN###{Storage} -->
            <p id="go21" class=nav1 onclick="go(21)"><a>Storage</a></p>
            <!-- ###END###{Storage} -->
            <!-- ###BEGIN###{NetworkSettings} -->
            <p id="go8" class=nav1 onclick="go(8)"><a>Network Settings</a></p>
            <!-- ###END###{NetworkSettings} -->
            <!-- ###BEGIN###{RemoteAccess} -->
            <p id="go17" class=nav1 onclick="go(17)"><a>Internet Settings</a></p>
            <!-- ###END###{RemoteAccess} -->
            <!-- ###BEGIN###{Certificates} -->
            <p id="go16" class=nav1 onclick="go(16)"><a>Security Settings</a></p>
            <!-- ###END###{Certificates} -->
            <!-- ###BEGIN###{AgentPresence} -->
            <p id="go19" class=nav1 onclick="go(19)"><a>Agent Presence</a></p>
            <!-- ###END###{AgentPresence} -->
            <!-- ###BEGIN###{SystemDefense} -->
            <p id="go18" class=nav1 onclick="go(18)"><a>System Defense</a></p>
            <!-- ###END###{SystemDefense} -->
            <p id="go11" class=nav1 onclick="go(11)"><a>User Accounts</a></p>
            <!-- ###BEGIN###{EventSubscriptions} -->
            <p id="go22" class=nav1 onclick="go(22)"><a>Subscriptions</a></p>
            <!-- ###END###{EventSubscriptions} -->
            <!-- ###BEGIN###{Alarms} -->
            <p id="go23" class=nav1 onclick="go(23)"><a>Wake Alarms</a></p>
            <!-- ###END###{Alarms} -->
            <!-- ###BEGIN###{Scripting-Editor} -->
            <p id="go20" class=nav1 onclick="go(20)"><a>Script Editor</a></p>
            <!-- ###END###{Scripting-Editor} -->
            <!-- ###BEGIN###{WsmanBrowser} -->
            <p id="go12" class=nav1 onclick="go(12)"><a>WSMAN Browser</a></p>
            <!-- ###END###{WsmanBrowser} -->
            <!-- ###BEGIN###{Storage} -->
            <!-- ###BEGIN###{Mode-Firmware} -->
            <!-- <div id=storagelinks style=margin-top:4px></div> -->
            <!-- ###END###{Mode-Firmware} -->
            <!-- ###END###{Storage} -->
            <!-- ###BEGIN###{Look-ISDU} -->
            <img id="id_isdu-image1" src="images-isdu/TabConfig.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image2" src="images-isdu/TabConnection.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image3" src="images-isdu/TabDesktop.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image4" src="images-isdu/TabDiscovery.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image5" src="images-isdu/TabEvents.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image6" src="images-isdu/TabNetwork.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image7" src="images-isdu/TabPolicies.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image8" src="images-isdu/TabRemote.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <!-- ###END###{Look-ISDU} -->
            <!-- ###BEGIN###{Look-BrandedCommander} -->
            <!-- ###BEGIN###{!Mode-Firmware} -->
            <img id="id_isdu-image1" src="images-BrandedCommander/TabConfig.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image2" src="images-BrandedCommander/TabConnection.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image3" src="images-BrandedCommander/TabDesktop.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image4" src="images-BrandedCommander/TabDiscovery.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image5" src="images-BrandedCommander/TabEvents.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image6" src="images-BrandedCommander/TabNetwork.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image7" src="images-BrandedCommander/TabPolicies.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <img id="id_isdu-image8" src="images-BrandedCommander/TabRemote.png" style="position:fixed;bottom:16px;left:32px;display:none" />
            <!-- ###END###{!Mode-Firmware} -->
            <!-- ###END###{Look-BrandedCommander} -->
        </div>
        <div id="id_mainarea" class=maincell>
            <!-- ###BEGIN###{IDER} -->
            <div id="id_iderstatus" style="position:relative;height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none;z-index:1000">
                <div style="float:right">
                    <input id="IDERDiskMapButton" type="button" value="Disk Map" onclick="iderToggleDiskMap()" />
                    <input type="button" value="Stop IDE-R Session" onclick="iderStop()" />
                </div>
                <div style="font-size:16px;padding-top:2px">&nbsp;<span id="id_iderstatusstr"></span></div>
                <div id="iderHeatmap" style="z-index:1000;position:absolute;top:31px;right:8px;border:1px solid black;box-shadow: 0px 0px 10px;border-radius:5px;padding:8px;width:600px;background-color:#99CC99;display:none">
                    <div id="floppyHeatMap" style="display:none">
                        <div id="floppyHeatMapText" style="margin:2px">Floppy, blocks are 512 bytes.</div>
                        <canvas id="floppyHeatMapCanvas" width="600" height="0"></canvas>
                    </div>
                    <div id="cdromHeatMap" style="display:none">
                        <div id="cdromHeatMapText" style="margin:2px">CDROM, blocks are 2048 bytes.</div>
                        <canvas id="cdromHeatMapCanvas" width="600" height="0"></canvas>
                    </div>
                </div>
            </div>
            <!-- ###END###{IDER} -->
            <!-- ###BEGIN###{Scripting} -->
            <div id="id_scriptstatus" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none;overflow:hidden">
                <div style="float:right"><input type="button" value="Stop Script" onclick="script_Stop()" /></div>
                <div style="font-size:16px;padding-top:2px;overflow:hidden">&nbsp;<b>Running Script</b><span style="overflow:hidden" id="id_scriptstatusstr"></span></div>
            </div>
            <!-- ###END###{Scripting} -->
            <!-- ###BEGIN###{VersionWarning} -->
            <div id="id_versionWarning" style="height:21px;background:#8fac8d;padding:5px;margin-bottom:1px;display:none">
                <div style="font-size:16px;float:right;cursor:pointer;padding-right:5px;padding-left:5px;padding-top:2px;font-size:15px" onclick="QV('id_versionWarning', false)">&#x2716;</div>
                <!-- ###BEGIN###{Mode-NodeWebkit} -->
                <div style="font-size:14px;padding-top:2px">&nbsp;<b>This computer's firmware should be updated,&nbsp;<a style="cursor:pointer" onclick="require('nw.gui').Shell.openExternal('https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00075&languageid=en-fr')"><u>please check here</u></a>.</b></div>
                <!-- ###END###{Mode-NodeWebkit} -->
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <div style="font-size:14px;padding-top:2px">&nbsp;<b>This computer's firmware should be updated,&nbsp;<a style="cursor:pointer" href="https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00075&languageid=en-fr" rel="noreferrer noopener" target="_blank" ><u>please check here</u></a>.</b></div>
                <!-- ###END###{!Mode-NodeWebkit} -->
            </div>
            <!-- ###END###{VersionWarning} -->
            <!-- ###BEGIN###{Storage} -->
            <div id="id_mainarea_frame" style="width:100%;height:100%">
                <iframe id="id_StorageIFrame" style=width:100%;height:100%;border:0></iframe>
            </div>
            <!-- ###END###{Storage} -->
            <div id="id_mainarea_pad" style="padding:8px;overflow-x:hidden">
                <div id="p0">
                    <h1>Loading...</h1>
                </div>
                <div id="p1" style="display:none">
                    <h1>System Status</h1>
                    <span id="id_TableSysStatus"></span>
                </div>
                <!-- ###BEGIN###{HardwareInfo} -->
                <div id="p2" style="display:none">
                    <h1 style="margin-bottom:16px">Hardware Information</h1>
                    <span id="id_TableSysInfo"></span>
                </div>
                <!-- ###END###{HardwareInfo} -->
                <!-- ###BEGIN###{EventLog} -->
                <div id="p6" style="display:none">
                    <h1>Event Log</h1>
                    <span id="id_TableEventLog"></span>
                    <span id="id_TableEventLog2"></span>
                </div>
                <!-- ###END###{EventLog} -->
                <!-- ###BEGIN###{NetworkSettings} -->
                <div id="p8" style="display:none">
                    <h1>Network Settings</h1>
                    <span id="id_TableNetworkSettingsSpan"></span>
                    <!-- ###BEGIN###{Wireless} -->
                    <span id="id_TableWifi2"></span>
                    <!-- ###END###{Wireless} -->
                    <!-- ###BEGIN###{NetAuth} -->
                    <span id="id_TableNetAuth"></span>
                    <!-- ###END###{NetAuth} -->
                </div>
                <!-- ###END###{NetworkSettings} -->
                <div id="p11" style="display:none">
                    <h1>User Accounts</h1>
                    <span id="id_TableUserAccounts"></span>
                </div>
                <!-- ###BEGIN###{WsmanBrowser} -->
                <div id="p12" style="display:none">
                    <h1>WSMAN Browser</h1>
                    <div>
                        <table class=log1 cellpadding=0 cellspacing=0 style='width:100%;border-radius:8px'>
                            <tr>
                                <td>
                                    <div style="padding:4px">
                                        <select id="id_QuerySelect" multiple="multiple" style="width:100%;height:120px"></select>
                                    </div>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <input id="id_p12querybutton" type="button" value="Query" style='margin: 4px' onclick="wsmanQuery()">
                                    <input type="button" value="Clear" style='margin: 4px' onclick="QH('id_wsresults', '')">
                                    <input id="idx_browserFilter" placeholder="Filter" style='margin: 4px' onkeyup="wsmanFilter()">
                                </td>
                            </tr>
                        </table>
                    </div>
                    <br>
                    <div class="us" id="id_wsresults"></div>
                </div>
                <!-- ###END###{WsmanBrowser} -->
                <!-- ###BEGIN###{Terminal} -->
                <div id="p13" style="display:none;min-width:780px">
                    <h1>Serial-over-LAN Terminal</h1>
                    <br>
                    <div id="id_p13warning1" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
                        <div class="icon2" style="float:left;margin:7px"></div><div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel&reg; AMT Redirection port or Serial-over-LAN feature is disabled<span id="id_p13warninga">, click here to enable it.</span></div>
                    </div>
                    <!-- ###BEGIN###{PowerControl} -->
                    <div id="id_p13warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()">
                        <div class="icon2" style="float:left;margin:7px"></div><div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
                    </div>
                    <!-- ###END###{PowerControl} -->
                    <table cellpadding="0" cellspacing="0" style="width:100%;padding:0px;padding:0px;margin-top:0px">
                        <tr>
                            <td style="padding-top:2px;padding-bottom:2px;background:#CCC">
                                <div style="float:right; text-align:right">
                                    <input onkeyup="sendTermInputKeys(event)" autocorrect="off" autocapitalize="off" style="opacity:0;width:0;height:0;font-size:1px" onblur="keyInputBlur()">
                                    <span id="id_p13power"></span>&nbsp;
                                    <!-- ###BEGIN###{Mode-MeshCentral2} -->
                                    <div id="termRecordIcon" title="Server is recording this session" style="display:none;float:right;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-right:4px"></div>
                                    <!-- ###END###{Mode-MeshCentral2} -->
                                    <!-- ###BEGIN###{PowerControl} -->
                                    <input type="button" onkeypress="return false" onkeydown="return false" class="cadbutton" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px">
                                    <!-- ###END###{PowerControl} -->
                                    <!-- ###BEGIN###{IDER} -->
                                    <!-- ###BEGIN###{Mode-MeshCentral2} -->
                                    <input type="button" id="idx_SIDER1" value="SIDER" title="Start server-side remote disk mount operation" onkeypress="return false" onkeydown="return false" onclick="iderServerStart()" style="margin-right:3px">
                                    <!-- ###END###{Mode-MeshCentral2} -->
                                    <input type="button" id="idx_IDER1" value="IDER" title="Start remote disk mount operation" onkeypress="return false" onkeydown="return false" onclick="iderStart(event)" style="margin-right:3px">
                                    <!-- ###END###{IDER} -->
                                    <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                                    <!-- ###BEGIN###{FileSaver} -->
                                    <input id="idx_terminalCaptureButton" type="button" onkeypress="return false" onkeydown="return false" class="cadbutton" value="Start Capture" title="Toggle start/stop of terminal capture, when stopping the content of the capture buffer will be saved to a file." onclick="terminalCaptureToggle(event)" style="margin-right:3px">
                                    <!-- ###END###{FileSaver} -->
                                    <!-- ###BEGIN###{TerminalReplay} -->
                                    <!-- <input id="idx_terminalReplayButton" type="button" onkeypress="return false" onkeydown="return false" class="cadbutton" value="Replay Capture" onclick="terminalReplay()" style="margin-right:3px"> -->
                                    <!-- ###END###{TerminalReplay} -->
                                    <!-- ###END###{!Mode-NodeWebkit} -->
                                </div>
                                <div>
                                    &nbsp;<input type="button" id="idx_connectbutton2" value="Connect" onclick="connectTerminal(event)" disabled="disabled">
                                    &nbsp;<span id="id_termstatus">Disconnected.</span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <td style="background:#000;text-align:center"><pre id="Term"></pre></td>
                        </tr>
                        <tr>
                            <td style="padding-top:2px;padding-bottom:2px;background:#CCC">
                                <div style="float:right;text-align:right">
                                    <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event);return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr();Q('id_tcrbutton').blur()">
                                    <!-- ###BEGIN###{TerminalSize} -->
                                    <input id="id_tsizebutton" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event); return false" class="bottombutton" value="80x25" title="Toggle terminal size" onclick="termToggleSize();Q('id_tsizebutton').blur()">
                                    <!-- ###END###{TerminalSize} -->
                                    <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event);return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx();Q('id_tfxkeysbutton').blur()">
                                    <!-- ###BEGIN###{Terminal-Enumation-All} -->
                                    <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event);return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType();Q('id_ttypebutton').blur()">&nbsp;
                                    <!-- ###END###{Terminal-Enumation-All} -->
                                </div>
                                <div>
                                    <!-- ###BEGIN###{Mode-NodeWebkit} -->
                                    <input id="id_toolbtncc" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event); return false" class="bottombutton" value="Ctl-C" onclick="termSendKey(3);Q('id_toolbtncc').blur()">
                                    <input id="id_toolbtncx" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event); return false" class="bottombutton" value="Ctl-X" onclick="termSendKey(24);Q('id_toolbtncx').blur()">
                                    <input id="id_toolbtnes" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event); return false" class="bottombutton" value="ESC" onclick="termSendKey(27);Q('id_toolbtnes').blur()">
                                    <input id="id_toolbtnbs" type="button" onkeypress="return false" onkeydown="if (event.keyCode == 13) handleKeyPress(event); return false" class="bottombutton" value="Backspace" onclick="termSendKey(8);Q('id_toolbtnbs').blur()">
                                    <!-- ###END###{Mode-NodeWebkit} -->
                                    <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                                    <span id="termkeysspan">
                                        <select style="margin-left:6px" id="termkeys">
                                            <option value=3>Ctrl-C</option>
                                            <option value=24>Ctrl-X</option>
                                            <option value=27>ESC</option>
                                            <option value=8>Backspace</option>
                                            <option value=1001>F1</option>
                                            <option value=1002>F2</option>
                                            <option value=1003>F3</option>
                                            <option value=1004>F4</option>
                                            <option value=1005>F5</option>
                                            <option value=1006>F6</option>
                                            <option value=1007>F7</option>
                                            <option value=1008>F8</option>
                                            <option value=1009>F9</option>
                                            <option value=1010>F10</option>
                                            <option value=1011>F11</option>
                                            <option value=1012>F12</option>
                                        </select>
                                        <input id=TermWD type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="termSendKeys()">
                                        &nbsp;
                                    </span>
                                    <!-- ###END###{!Mode-NodeWebkit} -->
                                    <input id="id_tpastebutton" type="button" onkeypress="return false" onkeydown="return false" class="cadbutton" value="Paste" disabled="disabled" onclick="setDialogMode(3,'Paste',3,termPaste)">
                                </div>
                            </td>
                        </tr>
                    </table>
                </div>
                <!-- ###END###{Terminal} -->
                <!-- ###BEGIN###{Desktop} -->
                <div id="p14" style="display:none;min-width:780px">
                    <div id="id_rdheader"><h1>Remote Desktop</h1><br></div>
                    <div id="id_p14warning1" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
                        <div class="icon2" style="float:left;margin:7px"></div><div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel&reg; AMT Redirection port or KVM feature is disabled<span id="id_p14warninga">, click here to enable it.</span></div>
                    </div>
                    <!-- ###BEGIN###{PowerControl} -->
                    <div id="id_p14warning2" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showPowerActionDlg()">
                        <div class="icon2" style="float:left;margin:7px"></div><div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Remote computer is not powered on, click here to issue a power command.</div>
                    </div>
                    <!-- ###END###{PowerControl} -->
                    <table cellpadding="0" cellspacing="0" style="width: 100%; padding: 0px; padding: 0px; margin-top: 0px">
                        <tr>
                            <td style="padding-top: 2px;padding-bottom:2px;background: #CCC">
                                <div style="float:right; text-align:right">
                                    <span id="id_p14power"></span>&nbsp;
                                    <div class='rb' title="Rotate Left" onclick="drotate(-1)">&olarr;</div>
                                    <div class='rb' title="Rotate Right" onclick="drotate(1)">&orarr;</div>
                                    <!-- ###BEGIN###{Mode-MeshCentral2} -->
                                    <div id="deskRecordIcon" title="Server is recording this session" style="display:none;float:right;background-color:red;width:12px;height:12px;border-radius:6px;margin-top:5px;margin-right:4px"></div>
                                    <!-- ###END###{Mode-MeshCentral2} -->
                                    <input id="idx_deskFullBtn" type="button" title="Toggle full screen mode" onkeypress="return false" onkeydown="return false" value="Full" onclick="deskToggleFull()" style="margin-right:3px">
                                    <!-- ###BEGIN###{DesktopFocus} -->
                                    <input id="idx_deskFocusBtn" type="button" title="Toggle focus mode, when active only the region around the mouse is updated" onkeypress="return false" onkeydown="return false" value="Focus All" onclick="deskToggleFocus()" style="margin-right:3px">
                                    <!-- ###END###{DesktopFocus} -->
                                    <!-- ###BEGIN###{FileSaver} -->
                                    <!-- ###BEGIN###{!DesktopRecorder} -->
                                    <input id="idx_deskSaveBtn" type="button" title="Save a screenshot of the remote desktop" onkeypress="return false" onkeydown="return false" value="Save..." onclick="deskSaveImage()" style="margin-right:3px">
                                    <!-- ###END###{!DesktopRecorder} -->
                                    <!-- ###END###{FileSaver} -->
                                    <input type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()" style="margin-right:3px">
                                    <!-- ###BEGIN###{IDER} -->
                                    <!-- ###BEGIN###{Mode-MeshCentral2} -->
                                    <input type="button" id="idx_SIDER2" value="SIDER" title="Start server-side remote disk mount operation" onkeypress="return false" onkeydown="return false" onclick="iderServerStart()" style="margin-right:3px">
                                    <!-- ###END###{Mode-MeshCentral2} -->
                                    <input type="button" id="idx_IDER2" value="IDER" title="Start remote disk mount operation" onkeypress="return false" onkeydown="return false" onclick="iderStart(event)" style="margin-right:3px">
                                    <!-- ###END###{IDER} -->
                                    <!-- ###BEGIN###{PowerControl} -->
                                    <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="margin-right:3px">
                                    <!-- ###END###{PowerControl} -->
                                </div>
                                <div>
                                    <div id="idx_deskFullBtn2" onclick="deskToggleFull()" style="float:left;cursor:pointer;font-size:15px;display:none">&nbsp;&#x2716;</div>
                                    &nbsp;<input type="button" id="idx_connectbutton1" value="Connect" onclick="connectDesktopButton(event)" onkeypress="return false" onkeydown="return false" disabled="disabled">
                                    &nbsp;<span id="id_deskstatus">Disconnected.</span>
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <td id="id_DeskParent" style="background:black;text-align:center;position:relative">
                                <!-- ###BEGIN###{DesktopFocus} -->
                                <div id="DeskFocus" style="color:transparent;border:3px dotted rgba(255,0,0,.2);position:absolute;border-radius:5px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)"></div>
                                <!-- ###END###{DesktopFocus} -->
                                <!-- ###BEGIN###{DesktopInband} -->
                                <canvas id="Desk" width=640 height=400 style="-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" onwheel="dmousewheel(event)" moz-opaque></canvas>
                                <!-- ###END###{DesktopInband} -->
                                <!-- ###BEGIN###{!DesktopInband} -->
                                <canvas id="Desk" width=640 height=400 style="-ms-touch-action:none;margin-left:0px" oncontextmenu="return false" onmousedown="dmousedown(event)" onmouseup="dmouseup(event)" onmousemove="dmousemove(event)" moz-opaque></canvas>
                                <!-- ###END###{!DesktopInband} -->
                            </td>
                        </tr>
                        <tr>
                            <td style="padding-top:2px;padding-bottom:2px;background:#CCC">
                                <!--
                        <div style="float:right; text-align:right">
                            <select id="specialkeylist" onkeypress="return false"></select>
                            <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" onclick="sendSpecialKey()">&nbsp;
                        </div>
                        -->
                                <!-- ###BEGIN###{DesktopClipboard} -->
                                <input id="id_DeskKvmClipButton" value="Clipboard" type="button" style="float:right;display:none" onclick=deskClipboard() />
                                <!-- ###END###{DesktopClipboard} -->
                                <!-- ###BEGIN###{FileSaver} -->
                                <!-- ###BEGIN###{DesktopRecorder} -->
                                <div id="id_DeskRecorderTools" style=float:right>
                                    <div id=DeskRecordButton class="videoIcon" title="Record remote desktop session to file" onclick=deskRecordSession()></div>
                                    <div id=DeskSaveImageButton class="cameraIcon" title="Save a screenshot of the remote desktop" onclick=deskSaveImage()></div>
                                </div>
                                <!-- ###END###{DesktopRecorder} -->
                                <!-- ###END###{FileSaver} -->
                                <!-- ###BEGIN###{Desktop-Multi} -->
                                <div id="id_DeskScreenSelector" style=float:right></div>
                                <!-- ###END###{Desktop-Multi} -->
                                <div>
                                    &nbsp;
                                    <span id="deskkeysspan">
                                        <select style="margin-left:6px" id="deskkeys">
                                            <option value=0>Win</option>
                                            <option value=1>Win+Down</option>
                                            <option value=2>Win+Up</option>
                                            <option value=3>Win+L</option>
                                            <option value=4>Win+M</option>
                                            <option value=20>Win+R</option>
                                            <option value=23>Win+Left</option>
                                            <option value=24>Win+Right</option>
                                            <option value=5>Shift+Win+M</option>
                                            <option value=19>Alt-Tab</option>
                                            <option value=21>Alt-F4</option>
                                            <option value=22>Ctrl-W</option>
                                            <option value=6>F1</option>
                                            <option value=7>F2</option>
                                            <option value=8>F3</option>
                                            <option value=9>F4</option>
                                            <option value=10>F5</option>
                                            <option value=11>F6</option>
                                            <option value=12>F7</option>
                                            <option value=13>F8</option>
                                            <option value=14>F9</option>
                                            <option value=15>F10</option>
                                            <option value=16>F11</option>
                                            <option value=17>F12</option>
                                            <option value=25>Enter</option>
                                            <!-- <option value=18>LS+LA+PrtSc</option> -->
                                        </select>
                                        <input id=DeskWD type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
                                        &nbsp;
                                    </span>
                                    <input id=id_DeskCAD type=button value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">&nbsp;
                                    <!-- ###BEGIN###{DesktopType} -->
                                    <input id=id_DeskType type=button value="Type" onkeypress="return false" onkeydown="return false" onclick="deskShowTypeDialog()">&nbsp;
                                    <!-- ###END###{DesktopType} -->
                                    <span id=id_DeskSBspan><input id=id_DeskSB type=checkbox> Blank Screen&nbsp;</span>
                                    <span id=id_DeskVOspan><input id=id_DeskVO type=checkbox> View only&nbsp;</span>
                                </div>
                            </td>
                        </tr>
                    </table>
                </div>
                <!-- ###END###{Desktop} -->
                <!-- ###BEGIN###{AuditLog} -->
                <div id="p15" style="display:none">
                    <span id="id_TableAuditLog1"></span>
                    <h1>Audit Log</h1>
                    <span id="id_TableAuditLog2"></span>
                </div>
                <!-- ###END###{AuditLog} -->
                <!-- ###BEGIN###{Certificates} -->
                <div id="p16" style="display:none">
                    <h1>Security Settings</h1>
                    <span id="id_TableCerts"></span>
                </div>
                <!-- ###END###{Certificates} -->
                <!-- ###BEGIN###{RemoteAccess} -->
                <div id="p17" style="display:none">
                    <h1>Internet Settings</h1>
                    <span id="id_TableRemoteAccess"></span>
                </div>
                <!-- ###END###{RemoteAccess} -->
                <!-- ###BEGIN###{SystemDefense} -->
                <div id="p18" style="display:none">
                    <h1>System Defense</h1>
                    <span id="id_TableSystemDefense"></span>
                </div>
                <!-- ###END###{SystemDefense} -->
                <!-- ###BEGIN###{AgentPresence} -->
                <div id="p19" style="display:none">
                    <h1>Agent Presence</h1>
                    <span id="id_TableSystemAgentPresence"></span>
                </div>
                <!-- ###END###{AgentPresence} -->
                <!-- ###BEGIN###{Scripting-Editor} -->
                <div id="p20" style="display:none">
                    <h1>Script Editor</h1>
                    <div class=log1 style="padding:5px;border-radius:5px">
                        <div id='EditScriptStatus' style="float:right;font-weight:bold;padding:5px">Stopped</div>
                        <div>
                            <input type="button" value="View Editor" title="Switch to script line editor view" id="viewEditorButton" onclick="scriptViewButton(0)" />
                            <input type="button" value="View Builder" title="Switch to block editor view" id="viewBuilderButton" onclick="scriptViewButton(1)" />
                            <input type="button" value="New..." title="Clear the script editor" onclick="script_newScriptDlg()" />
                            <input type="button" value="Load..." title="Load a script from file" onclick="script_runScriptDlg()" />
                            <!-- ###BEGIN###{FileSaver} -->
                            <input type="button" value="Save..." title="Save a script to file" onclick="script_saveScript(event)" />
                            <!-- ###END###{FileSaver} -->
                            <input type="button" value="Restart" title="Compile the script and get ready to run it from the start" onclick="resetScriptButton()" />
                            <input type="button" value="Continue" title="Run the script from the current execution point" onclick="runScriptButton()" />
                            <input type="button" value="Break" title="Pause the execution of the script" onclick="breakScriptButton()" />
                            <input type="button" value="Step" title="Execute one step of the script" onclick="stepScriptButton()" />
                        </div>
                    </div>
                    <div id="scriptbuilder" style="display:none">
                        <h2>Script Builder</h2>
                        <div style="padding:0;margin:0">
                            <div style="width:250px;height:400px;float:left;padding:0;margin:0;padding-right:3px">
                                <input id="blockfilter" style="width:inherit;height:24px;padding:0;margin:0;border:1px solid gray;margin-bottom:1px" placeholder="Filter blocks..." onkeyup="script_fonfilterchanged()" />
                                <div id="blocks" style="width:inherit;height:373px;border:1px solid gray;overflow-y:scroll;padding:0;margin:0"></div>
                            </div>
                            <div id="scriptblocks" style="width:auto;height:400px;padding:0;margin:0;border:1px solid gray;overflow-y:scroll" ondrop="script_fondrop(event, this)" onclick="script_fonclick(event)"></div>
                        </div>
                    </div>
                    <div id="scripteditor">
                        <h2>Script</h2>
                        <textarea id="scriptarea" style="width:100%;height:176px;resize:vertical;margin:0;padding:0;font-family:Arial,Helvetica,sans-serif" spellcheck=false></textarea>
                        <div style="display:none">
                            <br /><h2>Compiled Script</h2>
                            <textarea id="compiledarea" style="width:100%;height:16px;resize:vertical;margin:0;padding:0" spellcheck=false></textarea>
                            <br />
                        </div>
                        <h2>Variables</h2>
                        <div id="variables" style="width:100%;height:200px;resize:vertical;border:1px solid gray;overflow:scroll;margin:0;padding:0;user-select:text;-webkit-user-select:text;-khtml-user-select:text;-moz-user-select:text;-ms-user-select:text"></div>
                    </div>
                    <h2>Console</h2>
                    <textarea id="console" style="width:100%;height:80px;resize:vertical;margin:0;padding:0;user-select:text;-webkit-user-select:text;-khtml-user-select:text;-moz-user-select:text;-ms-user-select:text" readonly></textarea>
                </div>
                <!-- ###END###{Scripting-Editor} -->
                <!-- ###BEGIN###{Storage} -->
                <div id="p21" style="display:none">
                    <h1>Storage</h1>
                    <span id="id_TableSystemStorage"></span>
                </div>
                <!-- ###END###{Storage} -->
                <!-- ###BEGIN###{EventSubscriptions} -->
                <div id="p22" style="display:none">
                    <h1>Event Subscriptions</h1>
                    <span id="id_TableEventSubscriptions"></span>
                </div>
                <!-- ###END###{EventSubscriptions} -->
                <!-- ###BEGIN###{Alarms} -->
                <div id="p23" style="display:none">
                    <h1>Wake Alarms</h1>
                    <span id="id_TableAlarm"></span>
                </div>
                <!-- ###END###{Alarms} -->
                <!-- ###BEGIN###{DesktopInbandFiles} -->
                <div id="p24" style="display:none;position:absolute;top:0px;bottom:0px;left:8px;right:24px">
                    <h1>Files</h1><br/>
                    <table id="p24toolbar" style="width:100%;position:absolute;top:35px" cellpadding="0" cellspacing="0">
                        <tr>
                            <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
                                <div id="p24rightOfButtons" style="float:right;margin-top:3px"></div>
                                <div>
                                    <input type=button id=p24FolderUp disabled="disabled" onclick="p24folderup()" value="Up" />&nbsp;
                                    <input type=button id=p24SelectAllButton disabled="disabled" onclick="p24selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24RenameFileButton disabled="disabled" value="Rename" onclick="p24renamefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24DeleteFileButton disabled="disabled" value="Delete" onclick="p24deletefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24NewFolderButton disabled="disabled" value="New Folder" onclick="p24createfolder()" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24UploadButton disabled="disabled" value="Upload" onclick="p24uploadFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24CutButton disabled="disabled" value="Cut" onclick="p24copyFile(1)" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24CopyButton disabled="disabled" value="Copy" onclick="p24copyFile(0)" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24PasteButton disabled="disabled" value="Paste" onclick="p24pasteFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
                                    <input type=button id=p24RefreshButton disabled="disabled" value="Refresh" onclick="p24folderup(9999)" onkeypress="return false" onkeydown="return false" />&nbsp;
                                </div>
                            </td>
                        </tr>
                        <tr>
                            <td style="background-color:#E4E9E7;height:28px">
                                <div style=float:right;margin-right:4px>
                                    <select id=p24sortdropdown onchange=p24updateFiles()>
                                        <option value=1 selected="selected">Sort by name</option>
                                        <option value=2>Sort by size</option>
                                        <option value=3>Sort by date</option>
                                        <option value=4>Descend by name</option>
                                        <option value=5>Descend by size</option>
                                        <option value=6>Descend by date</option>
                                    </select>
                                </div>
                                <div>&nbsp;&nbsp;<span id="p24currentpath"></span></div>
                            </td>
                        </tr>
                    </table>
                    <div id="p24filetable" style="width:100%;overflow:auto;-webkit-user-select:none;position:absolute;top:92px;bottom:30px">
                        <div id="p24bigok" style="width:256px;overflow:hidden;position:absolute;top:80px;width:100%;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
                        <div id="p24bigfail" style="width:256px;overflow:hidden;position:absolute;top:80px;width:100%;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
                        <span id="p24files"></span>
                    </div>
                    <table id="p24toolbarBottom" style="width:100%;position:absolute;bottom:10px" cellpadding=0 cellspacing=0>
                        <tr><td style="text-align:left;padding:3px;text-align:center;background-color:#D3D9D6">&nbsp;<span id="p24bottomstatus"></span></td></tr>
                    </table>
                </div>
                <!-- ###END###{DesktopInbandFiles} -->
            </div>
        </div>
    </div>
    <!-- ###BEGIN###{Mode-MeshCentral2} -->
    <div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial, Helvetica, sans-serif;border-radius:5px;position:fixed;overflow:hidden;top:75px;width:400px;max-height:550px;display:none">
    <!-- ###END###{Mode-MeshCentral2} -->
    <!-- ###BEGIN###{!Mode-MeshCentral2} -->
    <div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial, Helvetica, sans-serif;border-radius:5px;position:fixed;top:160px;width:400px;display:none">
    <!-- ###END###{!Mode-MeshCentral2} -->
        <div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
            <div id='id_dialogclose' style="float:right;padding:1px;margin-right:5px;cursor:pointer;font-size:15px" onclick="setDialogMode()">&#x2716;</div>
            <div id='id_dialogtitle' style="padding:5px"></div>
            <div style="width:100%;margin:6px"></div>
        </div>
        <div style="margin-right:16px;margin-left:8px">
            <div id="dialog1" style="margin:auto;text-align:center;margin:3px">
                <div id="id_dialogMessage" style="padding:10px"></div>
            </div>
            <div id="dialog2" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'><input id="d2username" style="float:right;width:200px" onkeyup="updateAccountDialog()"><div>Username</div></div>
                <div style='height:26px'><input id="d2password1" type="password" autocomplete=off style="float:right;width:200px" onkeyup="updateAccountDialog()"><div>Password*</div></div>
                <div style='height:26px'><input id="d2password2" type="password" autocomplete=off style="float:right;width:200px" onkeyup="updateAccountDialog()"><div>Confirm Password</div></div>
                <div id="id_d2permissions">
                    <div style='height:26px'><select id="d2permission" style="float:right;width:200px"><option value="0">Local</option><option value="1">Network</option><option value="2">Any</option></select><div>Permission</div></div>
                    <div>Granted Permissions</div>
                    <ul id="id_d2realms" style="list-style-type:none;height:100px;overflow:auto;width:100%;border: 1px solid #000;background-color:white;overflow-x:hidden;margin:0;padding:0"></ul>
                </div>
                <div style="font-size:10px"><br>*Minimum 8 characters with upper, lowercase, 0-9, and one of !@#$%^&amp;*()+-</div>
            </div>
            <!-- ###BEGIN###{Terminal} -->
            <div id="dialog3" style="margin:auto;text-align:center;margin:3px">
                <textarea id='d3pastetextarea' maxlength=4096 style="width:100%;height:200px;resize:none"></textarea>
            </div>
            <!-- ###END###{Terminal} -->
            <!-- ###BEGIN###{Mode-LMS} -->
            <div id="dialog4" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'><input id="d4username" placeholder="admin" style="float:right;width:200px" onkeyup="lmsUpdateLoginDialog(event, 1)"><div>Username</div></div>
                <div style='height:26px'><input id="d4password" type="password" autocomplete=off style="float:right;width:200px" onkeyup="lmsUpdateLoginDialog(event, 2)"><div>Password*</div></div>
                <div style="font-size:10px"><br>*Minimum 8 characters with upper, lowercase, 0-9, and one of !@#$%^&amp;*()+-</div>
            </div>
            <!-- ###END###{Mode-LMS} -->
            <!-- ###BEGIN###{ComputerSelector} -->
            <div id="dialog4" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'><input id="d4name" style="float:right;width:200px" onkeyup="updateComputerDialog()"><div>Friendly Name</div></div>
                <div style='height:26px'><input id="d4tags" list="d4devGroups" style="float:right;width:200px" placeholder="MyGroup"><div>Group Name</div></div>
                <div style='height:26px'><input id="d4hostname" style="float:right;width:200px" onkeyup="updateComputerDialog()"><div>Hostname</div></div>
                <div style='height:26px'><select id="d4security" style="float:right;width:200px" onchange="updateComputerDialog()"><option value="0">Digest / None<option value="1">Digest / TLS<option value="2">Kerberos / None<option value="3">Kerberos / TLS</select><div>Auth / Security</div></div>
                <div id="d4digest">
                    <div style='height:26px'><input id="d4username" value="admin" style="float:right;width:200px" onkeyup="updateComputerDialog()"><div>Username</div></div>
                    <div style='height:26px'><input id="d4password" type="password" autocomplete=off style="float:right;width:200px" onkeyup="updateComputerDialog()"><div>Password*</div></div>
                    <div style="font-size:10px"><br>*Minimum 8 characters with upper, lowercase, 0-9, and one of !@#$%^&amp;*()+-</div>
                </div>
                <div id="d4kerb">
                    <div style='height:26px'><input id="d4kerberos" style="float:right;width:200px" onkeyup="updateComputerDialog()" placeholder="computer.domain.com:16992" title="If this field is filled, this value will be used to request the Kerberos token instead of host:port."><div>Optional Token Request*</div></div>
                    <div style="font-size:10px"><br>*Alternate hostname for Kerberos token request</div>
                </div>
                <datalist id="d4devGroups"></datalist>
            </div>
            <!-- ###END###{ComputerSelector} -->
            <div id="dialog5" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'>
                    <select id="d5actionSelect" style="float:right;width:200px"></select>
                    <div>Power Action</div>
                </div>
                <div>
                    <span style="color:red">Warning:</span> Some power actions may result in data loss and may disconnect the desktop, terminal or disk redirection sessions.
                </div>
            </div>
            <div id="dialog6" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'><input id="d6ConsentText" style="float:right;width:200px" maxlength="6" onkeyup="consentChanged()" onkeypress="if (event.keyCode == 13) return dialogclose(1); else return numbersOnly(event)"><div>Consent Code</div></div>
                <div style='height:26px'><select id="d6Display" onchange="changeConsentDisplay()" style="float:right;width:200px"><option value="0">Primary display</option><option value="1">Secondary display</option><option id="d6ThirdDisplay" value="2" style="display:none">Third display</option></select><div>Consent Display</div></div>
            </div>
            <!-- ###BEGIN###{Desktop} -->
            <div id="dialog7" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'>
                    <select id="idx_d7desktopmode" style="float:right;width:200px"></select>
                    <div>Image Encoding</div>
                </div>
                <div id="d7decimationspan" style='height:26px'>
                    <select id="d7decimation" style="float:right;width:200px"><option value=0>Don't set</option><option value=1>Disabled</option><option value=2>Automatic</option><option value=3>Enabled</option></select>
                    <div>Downscaling</div>
                </div>
                <div style="height:80px">
                    <div style="float:right;border:1px solid #666;width:200px;height:80px;overflow-y:scroll;background-color:white">
                        <!-- ###BEGIN###{DesktopFocus} -->
                        <label><input type="checkbox" id='d7showfocus'>Show Focus Tool</label><br>
                        <!-- ###END###{DesktopFocus} -->
                        <label><input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor</label><br>
                        <label><input type="checkbox" id='d7showcad'>Show Ctrl-Alt-Del</label><br>
                        <label><input type="checkbox" id='d7limitFrameRate'>Limit Frame Rate</label><br>
                        <label><input type="checkbox" id='d7noMouseRotate'>Don't Rotate Mouse</label><br>
                        <label><input type="checkbox" id='d7kvmrmw'>Reverse Mouse Wheel</label><br>
                    </div>
                    <div>Other Settings</div>
                </div>
                <!-- ###BEGIN###{DesktopInband} -->
                <div id="d7softkvmsettings" style="display:none">
                    <h4 style="width:100%;border-bottom:1px solid gray">Software KVM</h4>
                    <div style="margin:3px 0 3px 0">
                        <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl">
                            <option value=50>50%</option>
                            <option value=40>40%</option>
                            <option selected=selected value=30>30%</option>
                            <option value=20>20%</option>
                            <option value=10>10%</option>
                            <option value=5>5%</option>
                            <option value=1>1%</option>
                        </select>
                        <div style="height:20px">Quality</div>
                    </div>
                    <div style="margin:3px 0 3px 0">
                        <select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
                            <option selected=selected value=1024>100%</option>
                            <option value=896>87.5%</option>
                            <option value=768>75%</option>
                            <option value=640>62.5%</option>
                            <option value=512>50%</option>
                            <option value=384>37.5%</option>
                            <option value=256>25%</option>
                            <option value=128>12.5%</option>
                        </select>
                        <div style="height:20px">Scaling</div>
                    </div>
                </div>
                <!-- ###END###{DesktopInband} -->
            </div>
            <!-- ###END###{Desktop} -->
            <!-- ###BEGIN###{!Mode-Firmware} -->
            <div id="dialog8" style="display:table;margin:3px">
                <div style="margin:3px 0 3px 0;padding-top:5px">
                    <input id="idx_d8username" value="admin" style="float:right;width:220px">
                    <div style="height:20px">Username</div>
                </div>
                <div style="margin:3px 0 3px 0">
                    <input id="idx_d8password" type="password" autocomplete=off style="float:right;width:220px">
                    <div style="height:20px">Password</div>
                </div>
            </div>
            <!-- ###END###{!Mode-Firmware} -->
            <div id="dialog9" style="margin:auto;margin:3px">
                <label style="display:block"><input type="checkbox" id='idx_d9redir'>Redirection Port</label>
                <label id="idx_d9kvm_div" style="display:block"><input type="checkbox" id='idx_d9kvm'>KVM Remote Desktop</label>
                <label style="display:block"><input type="checkbox" id='idx_d9ider'>IDE-Redirection<br></label>
                <label style="display:block"><input type="checkbox" id='idx_d9sol'>Serial-over-LAN<br></label>
            </div>
            <div id="dialog10" style="margin:auto;margin:3px">
                <label><input type="radio" name="d10" id='idx_d10none' value=0>Not Required<br></label>
                <label><input type="radio" name="d10" id='idx_d10kvm' value=1>Required for KVM only<br></label>
                <label><input type="radio" name="d10" id='idx_d10all' value=4294967295>Always Required<br></label>
            </div>
            <div id="dialog11" style="margin:auto;margin:3px">
                <div id="id_dialogOptions"></div>
            </div>
            <!-- ###BEGIN###{Wireless} -->
            <div id="dialog12" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'><input id="idx_d12name" style="float:right;width:200px" maxlength="32" onkeyup="updateWifiDialog()" title="Maximum 32 characters"><div title="Maximum 32 characters">Profile Name</div></div>
                <div style='height:26px'><input id="idx_d12ssid" style="float:right;width:200px" maxlength="32" onkeyup="updateWifiDialog()" title="Maximum 32 characters"><div title="Maximum 32 characters">SSID</div></div>
                <div style='height:26px'>
                    <select id="idx_d12pri" style="float:right;width:200px"  onclick="updateWifiDialog()"></select>
                    <div>Priority</div>
                </div>
                <div style='height:26px'>
                    <select id="idx_d12auth" style="float:right;width:200px" onclick="updateWifiDialog()"></select>
                    <div>Authentication</div>
                </div>
                <div style='height:26px'>
                    <select id="idx_d12enc" style="float:right;width:200px" onclick="updateWifiDialog()">
                        <option id="id_d12e4" value="4">CCMP-AES</option>
                        <option id="id_d12e3" value="3">TKIP-RC4</option>
                        <!--<option id="id_d12e2" value="2">WEP</option>-->
                        <!--<option id="id_d12e5" value="5">None</option>-->
                    </select>
                    <div>Encryption</div>
                </div>
                <div id="idx_d12pass">
                    <div style='height:26px'><input id="idx_d12password1" type="password" style="float:right;width:200px" maxlength="63" onkeyup="updateWifiDialog()" title="Length between 8 and 63 characters"><div title="Length between 8 and 63 characters">Password*</div></div>
                    <div style='height:26px'><input id="idx_d12password2" type="password" style="float:right;width:200px" maxlength="63" onkeyup="updateWifiDialog()" title="Length between 8 and 63 characters"><div title="Length between 8 and 63 characters">Confirm Password</div></div>
                </div>
                <!-- ###BEGIN###{NetAuth} -->
                <div id="idx_d12netauth" style="display:none">
                    <div id="idx_d12protocoldiv" style='height:26px'>
                        <select id='idx_d12protocol' style='float:right;width:200px' onchange=updateNetAuth2Dialog(event)>
                            <option value='0' selected="selected">EAP-TLS</option>
                            <option value='1'>EAP-TTLS/MSCHAPv2</option>
                            <option value='2'>PEAPv0/EAP-MSCHAPv2</option>
                            <option value='3'>PEAPv1/EAP-GTC</option>
                            <option value='4'>EAP-FAST/MSCHAPv2</option>
                            <option value='5'>EAP-FAST/GTC</option>
                            <option value='6'>EAP-FAST/TLS</option>
                        </select>
                        <div>Protocol</div>
                    </div>
                    <div id="idx_d12servernamediv" style='height:26px'><input id='idx_d12servername' style="float:right;width:200px" maxlength="80" onkeyup="updateNetAuthDialog()" title="Maximum 32 characters"><div title="Maximum 32 characters">Server Name</div></div>
                    <div id="idx_d12servernamecomparediv" style='height:26px'>
                        <select id='idx_d12servernamecompare' style="float:right;width:200px" onclick="updateNetAuth2Dialog()">
                            <option value='0' selected="selected">Full Name</option>
                            <option value='1'>Domain Suffix</option>
                        </select>
                        <div>Server Name Compare</div>
                    </div>
                    <div id="idx_d12domaindiv" style='height:26px'><input id="idx_d12domain" style="float:right;width:200px" maxlength="128" onkeyup="updateNetAuth2Dialog()" title="Maximum 128 characters"><div title="Maximum 128 characters">Domain</div></div>
                    <div id="idx_d12usernamediv" style='height:26px'><input id="idx_d12username" style="float:right;width:200px" maxlength="128" onkeyup="updateNetAuth2Dialog()" title="Maximum 128 characters"><div title="Maximum 128 characters">Username</div></div>
                    <div id="idx_d12passworddiv" style='height:26px'><input id="idx_d12password" type="password" style="float:right;width:200px" maxlength="32" onkeyup="updateNetAuth2Dialog()" title="Maximum length is 32 characters"><div title="Maximum length is 32 characters">Password</div></div>
                    <div id="idx_d12roamingidentitydiv" style='height:26px'><input id="idx_d12roamingidentity" style="float:right;width:200px" maxlength="80" onkeyup="updateNetAuth2Dialog()" title="Maximum 80 characters"><div title="Maximum 80 characters">Roaming Identity</div></div>
                    <div id="idx_d12pacdiv" style='height:26px'><input id="idx_d12pac" style="float:right;width:200px" maxlength="256" onkeyup="updateNetAuth2Dialog()" title="Maximum 256 characters"><div title="Maximum 256 characters">Protected Access Credentials</div></div>
                    <div id="idx_d12pacpassworddiv" style='height:26px'><input id="idx_d12pacpassword" type="password" style="float:right;width:200px" maxlength="256" onkeyup="updateNetAuth2Dialog()" title="Maximum length is 256 characters"><div title="Maximum length is 256 characters">PAC Password</div></div>
                    <div id="idx_d12clientcertdiv" style='height:26px'>
                        <select id="idx_d12clientcert" style="float:right;width:200px" onclick="updateNetAuth2Dialog()"></select>
                        <div>Client Certificate</div>
                    </div>
                    <div id="idx_d12servercertdiv" style='height:26px'>
                        <select id="idx_d12servercert" style="float:right;width:200px" onclick="updateNetAuth2Dialog()"></select>
                        <div>Server Issuer Cert</div>
                    </div>
                    <div id="idx_d12activeins0div" style='height:26px'>
                        <select id="idx_d12activeins0" style="float:right;width:200px" onclick="updateNetAuth2Dialog()">
                            <option value="1">Enabled</option>
                            <option value="0">Disabled</option>
                        </select>
                        <div>Active in S0</div>
                    </div>
                </div>
                <!-- ###END###{NetAuth} -->
            </div>
            <!-- ###END###{Wireless} -->
            <!-- ###BEGIN###{USBSetup} -->
            <div id="dialog13" style="margin:auto;margin:3px">
                <label><input type="checkbox" id='d13valid'>Valid Record<br></label>
                <span id="d13ScrambledRecordSpan"><label><input type="checkbox" id='d13scramble'>Scrambled Record</label><br></span>
            </div>
            <div id="dialog14" style="margin:auto;margin:3px">
                <div style='height:26px'>
                    <select id="idx_d14version" style="float:right;width:200px">
                        <option value="1">Version 1</option>
                        <option value="2">Version 2</option>
                        <option value="3">Version 3</option>
                        <option value="4">Version 4</option>
                    </select>
                    <div>Setup.bin version</div>
                </div>
                <div style='height:26px'>
                    <select id="idx_d14consume" style="float:right;width:200px">
                        <option value="1">Records will not be consumed</option>
                        <option value="0">Records will be consumed</option>
                    </select>
                    <div>Record consumption</div>
                </div>
            </div>
            <div id="dialog15" style="margin:auto;margin:3px">
                <input id="d15setupbinfile" type="file" style="width:100%" accept=".bin">
            </div>
            <div id="dialog16" style="margin:auto;margin:3px">
                <div style='height:26px'>
                    <select id="d16type" style="float:right;width:260px" onchange="usb_ond16typechange()" onclick="usb_ond16typechange()" onscroll="usb_ond16typechange()" onkeydown="usb_ond16typechange()"></select>
                    <div>Variable Type</div>
                </div>
                <div id="d16genericvalue" style='height:26px'>
                    <select id="idx_d16value1" style="float:right;width:260px"></select>
                    <input id="idx_d16value2" style="float:right;width:260px;display:none">
                    <div>Variable Value</div>
                </div>
                <div id="d16customvalue"></div>
            </div>
            <!-- ###END###{USBSetup} -->
            <!-- ###BEGIN###{ComputerSelector} -->
            <div id="dialog17" style="margin:auto;margin:3px">
                <input id="idx_d17computerlistfile" type="file" style="width:100%" accept=".json, .csv">
            </div>
            <div id="dialog18" style="margin:auto;margin:3px">
                <!-- ###BEGIN###{!Mode-NodeWebkit} -->
                <input id="idx_d18computerfilename" style="width:100%" value="computerlist.json">
                <!-- ###END###{!Mode-NodeWebkit} -->
                <!-- ###BEGIN###{Mode-NodeWebkit} -->
                <!-- <input id="idx_d18computersavefile" type="file" nwsaveas="computerlist.json" accept=".json"> -->
                <div style="text-align:left;height:26px;padding-top:6px">
                    <label><input id="d18usepassword" type="checkbox" style="float:left" onchange="saveComputerListUpdate()"><div>Use encryption. The file will contain Intel&reg; AMT credentials, saving using a password may help protect this data.</div></label>
                </div>
                <div id="d18showpassword" style="display:none;padding-top:16px">
                    <div style='height:26px'><input id="d18password1" type="password" autocomplete=off style="float:right;width:200px" onkeyup="saveComputerListUpdate()"><div>Password*</div></div>
                    <div style='height:26px'><input id="d18password2" type="password" autocomplete=off style="float:right;width:200px" onkeyup="saveComputerListUpdate()"><div>Confirm Password</div></div>
                    <div style="font-size:10px"><br>*Minimum 8 characters with upper, lowercase, 0-9, and one of !@#$%^&amp;*()+-</div>
                </div>
                <!-- ###END###{Mode-NodeWebkit} -->
            </div>
            <!-- ###END###{ComputerSelector} -->
            <!-- ###BEGIN###{FileSaver} -->
            <div id="dialog19" style="margin:auto;margin:3px">
                This will save the entire state of Intel&reg; AMT for this machine into file. Passwords will not be saved, but some sensitive data may be included.<br><br>
                <input id="idx_d19savestatefilename" style="width:100%" value="amtstate.json">
            </div>
            <!-- ###END###{FileSaver} -->
            <!-- ###BEGIN###{NetworkSettings} -->
            <div id="dialog20" style="margin:auto;margin:3px">
                <input type="radio" name="d20" id="d20a" value="0">Disabled<br>
                <input type="radio" name="d20" id="d20b" value="1">ICMP response<br>
                <input type="radio" name="d20" id="d20c" value="2">RMCP response<br>
                <input type="radio" name="d20" id="d20d" value="3">ICMP & RMCP response<br><br>
            </div>
            <div id="dialog21" style="margin:auto;margin:3px">
                <div id="id_d21ipaddrsync">
                    <label><input type="checkbox" name="d21" id="d21ipsync" onclick="updateIPSetupDlg()">Operating system IP address sync</label><br>
                </div>
                <label><input type="radio" name="d21" id="d21o0" onclick="updateIPSetupDlg()"><span id="d21l0"></span></label><br>
                <label><input type="radio" name="d21" id="d21o1" onclick="updateIPSetupDlg()"><span id="d21l1"></span></label><br>
                <div id="id_d21manualdiv">
                    <label><input type="radio" name="d21" id='d21o2' onclick="updateIPSetupDlg()"><span id="d21l2"></span></label><br><br>
                    <div style="margin-left:20px">
                        <div style="height:26px"><input id="idx_d21address" onkeyup="updateIPSetupDlg()" style="float:right;width:230px"><div>IP address</div></div>
                        <div style="height:26px" id="id_d21subnetdiv"><input id="idx_d21subnet" onkeyup="updateIPSetupDlg()" style="float:right;width:230px"><div>Subnet mark</div></div>
                        <div style="height:26px"><input id="idx_d21gateway" onkeyup="updateIPSetupDlg()" style="float:right;width:230px"><div>Gateway</div></div>
                        <div style="height:26px"><input id="idx_d21dns1" onkeyup="updateIPSetupDlg()" style="float:right;width:230px"><div>Primary DNS</div></div>
                        <div style="height:26px"><input id="idx_d21dns2" onkeyup="updateIPSetupDlg()" style="float:right;width:230px"><div>Alternate DNS</div></div>
                    </div>
                </div>
            </div>
            <div id="dialog23" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'>
                    <select id="idx_d23ddns" style="float:right;width:200px" onchange="showEditDnsDlgChange()">
                        <option value="0">Disabled</option>
                        <option value="1">Disabled, DHCP update</option>
                        <option value="2">Enabled</option>
                    </select>
                    <div>Dynamic DNS client</div>
                </div>
                <div style='height:26px'><input id="idx_d23interval" style="float:right;width:200px"><div>Update Interval (minutes)</div></div>
                <div style='height:26px'><input id="idx_d23ttl" style="float:right;width:200px"><div>TTL (seconds)</div></div>
                <div style="font-size:10px"><br>Defaut Interval is 1440 minutes, Default TTL is 900 seconds.</div>
            </div>
            <!-- ###END###{NetworkSettings} -->
            <!-- ###BEGIN###{PowerControl-Advanced} -->
            <div id="dialog24" style="margin:auto;margin:3px">
                <br>
                <div style=height:26px>
                    <select id="idx_d24Command" style="float:right;width:200px" onchange=showAdvPowerDlgChange()>
                        <option value=2>Power up</option>
                        <option value=10>Reset</option>
                        <option value=5>Power cycle</option>
                        <option value=8>Power down</option>
                        <option id="d24p500" value=500>OS Wake from Standby</option>
                        <option id="d24p501" value=501>OS Power Saving</option>
                        <option value=999>Set boot options</option>
                    </select>
                    <div>Remote Command</div>
                </div>
                <div style=height:80px>
                    <div id="idx_d24bootoptions" style="float:right;border:1px solid #666;width:200px;height:72px;overflow-y:scroll;background-color:white">
                        <div id=d24dBiosPause><label><input type=checkbox id=d24BiosPause onchange=showAdvPowerDlgChange()>BIOS Pause</label><br></div>
                        <div id=d24dBiosSecureBoot><label><input type=checkbox id=d24BiosSecureBoot onchange=showAdvPowerDlgChange()>Enforce Secure Boot</label><br></div>
                        <div id=d24dBiosSetup><label><input type=checkbox id=d24BiosSetup onchange=showAdvPowerDlgChange()>BIOS Setup</label><br></div>
                        <div id=d24dForceProgressEvents><label><input type=checkbox id=d24ForceProgressEvents onchange=showAdvPowerDlgChange()>Force progress events</label><br></div>
                        <div id=d24dLockPowerButton><label><input type=checkbox id=d24LockPowerButton onchange=showAdvPowerDlgChange()>Lock power button</label><br></div>
                        <div id=d24dLockResetButton><label><input type=checkbox id=d24LockResetButton onchange=showAdvPowerDlgChange()>Lock reset button</label><br></div>
                        <div id=d24dLockSleepButton><label><input type=checkbox id=d24LockSleepButton onchange=showAdvPowerDlgChange()>Lock sleep button</label><br></div>
                        <div id=d24dLockKeyboard><label><input type=checkbox id=d24LockKeyboard onchange=showAdvPowerDlgChange()>Lock keyboard</label><br></div>
                        <div id=d24dUserPasswordBypass><label><input type=checkbox id=d24UserPasswordBypass onchange=showAdvPowerDlgChange()>BIOS password bypass</label><br></div>
                        <div id=d24dReflashBios><label><input type=checkbox id=d24ReflashBios onchange=showAdvPowerDlgChange()>Reflash BIOS</label><br></div>
                        <div id=d24dSafeMode><label><input type=checkbox id=d24SafeMode onchange=showAdvPowerDlgChange()>Safe mode</label><br></div>
                        <div id=d24dUseIDER><label><input type=checkbox id=d24UseIDER onchange=showAdvPowerDlgChange()>Use IDER</label><br></div>
                        <div id=d24dSerialOverLan><label><input type=checkbox id=d24SerialOverLan onchange=showAdvPowerDlgChange()>Serial-over-LAN</label><br></div>
                        <div id=d24dSecureErase><label><input type=checkbox id=d24SecureErase onchange=showAdvPowerDlgChange()>Intel&reg; Remote Secure Erase</label><br></div>
                        <div id=d24dPlatformErase><label><input type=checkbox id=d24PlatformErase onchange=showAdvPowerDlgChange()>Remote Platform Erase</label><br></div>
                        <div id=d24dFirmwareReset><label><input type=checkbox id=d24FirmwareReset onchange=showAdvPowerDlgChange()>Clear Intel&reg; ME Settings</label><br></div>
                    </div>
                    <div>Boot Settings</div>
                </div>
                <div style=height:26px>
                    <select id="idx_d24ForceBootDevice" style="float:right;width:200px" onchange=showAdvPowerDlgChange()></select>
                    <div>Boot Source</div>
                </div>
                <div id="idx_d24bootSource" style=height:26px>
                    <select id="idx_d24BootMediaIndex" style="float:right;width:200px" onchange=showAdvPowerDlgChange()>
                        <option value=0>None</option>
                        <option value=1>Index 1</option>
                        <option value=2>Index 2</option>
                        <option value=3>Index 3</option>
                        <option value=3>Index 4</option>
                    </select>
                    <div>Boot Media</div>
                </div>
                <!-- ###BEGIN###{PowerControl-OneClick} -->
                <div id="idx_d24customBootSource" style=height:26px;display:none>
                    <select id="idx_d24customBootMediaIndex" onchange=showAdvPowerDlgChange() style="float:right;width:200px"></select>
                    <div>Boot Media</div>
                </div>
                <div id="idx_d24diskImage" style=height:26px>
                    <input id=idx_d24ocrBootFile type=file onchange=showAdvPowerDlgChange() style="float:right;width:200px" accept=".iso">                    
                    <div>Boot Image</div>
                </div>
                <div id="idx_d24diskImageUrl" style=height:26px>
                    <input id=idx_d24ocrBootUrl type=text onchange=showAdvPowerDlgChange() onkeyup=showAdvPowerDlgChange() placeholder="https://" style="float:right;width:200px">
                    <div>Boot URL</div>
                </div>
                <div id="idx_d24diskImageHttpTimeout" style=height:26px>
                    <input id=idx_d24ocrBootHttpBootTimeout type=text onchange=showAdvPowerDlgChange() onkeyup=showAdvPowerDlgChange() value="0" style="float:right;width:200px">
                    <div>Timeout (Seconds)</div>
                </div>
                <!-- ###END###{PowerControl-OneClick} -->
                <div style=height:26px id=idd_d24IDERBootDevice>
                    <select id="idx_d24IDERBootDevice" style="float:right;width:200px" onchange=showAdvPowerDlgChange()>
                        <option value=0>Boot to floppy</option>
                        <option value=1>Boot to CDROM</option>
                    </select>
                    <div>IDER Boot Device</div>
                </div>
                <div style=height:26px>
                    <select id="idx_d24Verbocity" style="float:right;width:200px" onchange=showAdvPowerDlgChange()>
                        <option value=0>System Default</option>
                        <option id="idx_d24Verbocity1" value=1>Quiet</option>
                        <option id="idx_d24Verbocity2" value=2>Verbose</option>
                        <option id="idx_d24Verbocity3" value=3>Blank Screen</option>
                    </select>
                    <div>Verbocity</div>
                </div>
                <div style=height:26px id=idd_d24RSEPass>
                    <div style="float:right;width:200px"><input type=password id=d24rsepass maxlength=32 style=float:right;width:100%></div>
                    <div>RSE Password</div>
                </div>
                <!-- ###BEGIN###{Mode-NodeWebkit} -->
                <div id=idd_d24RSEPassTlsWarn><div style=color:red><b>WARNING:</b> TLS is not used, password will be sent in the clear.</div></div>
                <!-- ###END###{Mode-NodeWebkit} -->
            </div>
            <!-- ###END###{PowerControl-Advanced} -->
            <!-- ###BEGIN###{Alarms} -->
            <div id="dialog25" style="margin:auto;margin:3px">
                <div style=text-align:left>
                    <div style=height:26px;margin-top:4px><input id=d25alarm_name style=float:right;width:180px maxlength=32 onkeyup=alertDialogUpdate()><div style=padding-top:4px>Alarm name</div></div>
                    <div style=height:26px;margin-top:4px>
                        <div style=float:right>
                            <input id=d25alarm_sdate style=width:180px maxlength=10 onkeyup=alertDialogUpdate() onkeypress="return numbersOnly(event,45)">
                        </div>
                        <div style=padding-top:4px>Wake date (year-month-day)</div>
                    </div>
                    <div style=height:26px;margin-top:4px>
                        <div style=float:right>
                            <input id=d25alarm_stime style=width:180px maxlength=10 onkeyup=alertDialogUpdate() onkeypress="return numbersOnly(event,58)">
                        </div>
                        <div style=padding-top:4px>Wake time (hour:min:sec)</div>
                    </div>
                    <div style=height:26px;margin-top:4px>
                        <div style=float:right>
                            <input id=d25alarm_interval style=width:180px maxlength=10 onkeyup=alertDialogUpdate() onkeypress="return numbersOnly(event,45)">
                        </div>
                        <div style=padding-top:4px>Interval (days-hours-min)</div>
                    </div>
                    <div style=height:26px;margin-top:4px>
                        <div style=float:right;width:180px>
                            <select id=d25alarm_doc style=width:100% onchange=showAdvPowerDlgChange()>
                                <option value=0>Keep alarm</option>
                                <option value=1>Delete on completion</option>
                            </select>
                        </div>
                        <div style=padding-top:4px>After wake</div>
                    </div>
                </div>
            </div>
            <!-- ###END###{Alarms} -->
            <div id="dialog26" style="margin:auto;margin:3px">
                <div id="d26rpediv">
                    <div>Remote Platform Erase (RPE)</div>
                    <label><input type="radio" name="d26b" id='idx_d26rpe1' value=2>Enabled<br></label>
                    <label><input type="radio" name="d26b" id='idx_d26rpe0' value=0>Disabled<br></label>
                    <hr />
                </div>
                <div>One One Click Recovery (OCR)</div>
                <label><input type="radio" name="d26a" id='idx_d26ocr1' value=1>Enabled<br></label>
                <label><input type="radio" name="d26a" id='idx_d26ocr0' value=0>Disabled<br></label>
            </div>
            <!-- ###BEGIN###{NetAuth} -->
            <div id="dialog27" style="margin:auto;margin:3px">
                <br>
                <div style='height:26px'>
                    <select id="idx_d27enabled" style="float:right;width:200px" onclick="updateNetAuthDialog()">
                        <option value="0">Disabled</option>
                        <option value="1">Enabled</option>
                    </select>
                    <div>Enabled</div>
                </div>
                <div id="idx_d27protocoldiv" style='height:26px'>
                    <select id='idx_d27protocol' style='float:right;width:200px' onclick='updateNetAuthDialog()'>
                        <option value='0' selected="selected">EAP-TLS</option>
                        <option value='1'>EAP-TTLS/MSCHAPv2</option>
                        <option value='2'>PEAPv0/EAP-MSCHAPv2</option>
                        <option value='3'>PEAPv1/EAP-GTC</option>
                        <option value='4'>EAP-FAST/MSCHAPv2</option>
                        <option value='5'>EAP-FAST/GTC</option>
                        <option value='6'>EAP-FAST/TLS</option>
                    </select>
                    <div>Protocol</div>
                </div>
                <div id="idx_d27servernamediv" style='height:26px'><input id='idx_d27servername' style="float:right;width:200px" maxlength="80" onkeyup="updateNetAuthDialog()" title="Maximum 32 characters"><div title="Maximum 32 characters">Server Name</div></div>
                <div id="idx_d27servernamecomparediv" style='height:26px'>
                    <select id='idx_d27servernamecompare' style="float:right;width:200px" onclick="updateNetAuthDialog()">
                        <option value='0' selected="selected">Full Name</option>
                        <option value='1'>Domain Suffix</option>
                    </select>
                    <div>Server Name Compare</div>
                </div>
                <div id="idx_d27domaindiv" style='height:26px'><input id="idx_d27domain" style="float:right;width:200px" maxlength="128" onkeyup="updateNetAuthDialog()" title="Maximum 128 characters"><div title="Maximum 128 characters">Domain</div></div>
                <div id="idx_d27usernamediv" style='height:26px'><input id="idx_d27username" style="float:right;width:200px" maxlength="128" onkeyup="updateNetAuthDialog()" title="Maximum 128 characters"><div title="Maximum 128 characters">Username</div></div>
                <div id="idx_d27passworddiv" style='height:26px'><input id="idx_d27password" type="password" style="float:right;width:200px" maxlength="32" onkeyup="updateNetAuthDialog()" title="Maximum length is 32 characters"><div title="Maximum length is 32 characters">Password</div></div>
                <div id="idx_d27roamingidentitydiv" style='height:26px'><input id="idx_d27roamingidentity" style="float:right;width:200px" maxlength="80" onkeyup="updateNetAuthDialog()" title="Maximum 80 characters"><div title="Maximum 80 characters">Roaming Identity</div></div>
                <div id="idx_d27pacdiv" style='height:26px'><input id="idx_d27pac" style="float:right;width:200px" maxlength="256" onkeyup="updateNetAuthDialog()" title="Maximum 256 characters"><div title="Maximum 256 characters">Protected Access Credentials</div></div>
                <div id="idx_d27pacpassworddiv" style='height:26px'><input id="idx_d27pacpassword" type="password" style="float:right;width:200px" maxlength="256" onkeyup="updateNetAuthDialog()" title="Maximum length is 256 characters"><div title="Maximum length is 256 characters">PAC Password</div></div>
                <div id="idx_d27clientcertdiv" style='height:26px'>
                    <select id="idx_d27clientcert" style="float:right;width:200px" onclick="updateNetAuthDialog()"></select>
                    <div>Client Certificate</div>
                </div>
                <div id="idx_d27servercertdiv" style='height:26px'>
                    <select id="idx_d27servercert" style="float:right;width:200px" onclick="updateNetAuthDialog()"></select>
                    <div>Server Issuer Cert</div>
                </div>
                <div id="idx_d27activeins0div" style='height:26px'>
                    <select id="idx_d27activeins0" style="float:right;width:200px" onclick="updateNetAuthDialog()">
                        <option value="0">Enabled</option>
                        <option value="1">Disabled</option>
                    </select>
                    <div>Active in S0</div>
                </div>
                <div id="idx_d27pxetimeoutdiv" style='height:26px'><input id="idx_d27pxetimeout" style="float:right;width:200px" onkeyup="updateNetAuthDialog()"><div>PXE Timeout</div></div>
            </div>
            <!-- ###END###{NetAuth} -->
        </div>
        <div style="padding:10px;margin-bottom:4px">
            <input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
            <input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
            <div style="height:25px"><input id="idx_dlgDeleteButton" type="button" value="Delete" style="width:80px;display:none" onclick="dialogclose(2)"></div>
        </div>
    </div>
    <!-- ###BEGIN###{ContextMenus} -->
    <div id="contextMenu" class="contextMenu" style="display:none"></div>
    <!-- ###END###{ContextMenus} -->
    <!-- ###BEGIN###{Mode-NodeWebkit} -->
    <!-- ###END###{Mode-NodeWebkit} -->
    <!-- ###BEGIN###{PowerControl} -->
    <!-- ###END###{PowerControl} -->
        <script type="text/javascript">
        // ###BEGIN###{!Look-BrandedCommander}
        var version = '0.9.6';
        // ###END###{!Look-BrandedCommander}
        // ###BEGIN###{Look-BrandedCommander}
        var version = '1.2.0';
        // ###END###{Look-BrandedCommander}
        var urlvars = {};
        var amtstack;
        var wsstack = null;
// ###BEGIN###{WsmanBrowser}
        var AllWsman = 'AMT_8021xCredentialContext,AMT_8021XProfile,AMT_ActiveFilterStatistics,AMT_AgentPresenceCapabilities,AMT_AgentPresenceInterfacePolicy,AMT_AgentPresenceService,AMT_AgentPresenceWatchdog,AMT_AgentPresenceWatchdogAction,AMT_AlarmClockService,IPS_AlarmClockOccurrence,AMT_AssetTable,AMT_AssetTableService,AMT_AuditLog,AMT_AuditPolicyRule,AMT_AuthorizationService,AMT_BootCapabilities,AMT_BootSettingData,AMT_ComplexFilterEntryBase,AMT_CRL,AMT_CryptographicCapabilities,AMT_EACCredentialContext,AMT_EndpointAccessControlService,AMT_EnvironmentDetectionInterfacePolicy,AMT_EnvironmentDetectionSettingData,AMT_EthernetPortSettings,AMT_EventLogEntry,AMT_EventManagerService,AMT_EventSubscriber,AMT_FilterEntryBase,AMT_FilterInSystemDefensePolicy,AMT_GeneralSettings,AMT_GeneralSystemDefenseCapabilities,AMT_Hdr8021Filter,AMT_HeuristicPacketFilterInterfacePolicy,AMT_HeuristicPacketFilterSettings,AMT_HeuristicPacketFilterStatistics,AMT_InterfacePolicy,AMT_IPHeadersFilter,AMT_KerberosSettingData,AMT_ManagementPresenceRemoteSAP,AMT_MessageLog,AMT_MPSUsernamePassword,AMT_NetworkFilter,AMT_NetworkPortDefaultSystemDefensePolicy,AMT_NetworkPortSystemDefenseCapabilities,AMT_NetworkPortSystemDefensePolicy,AMT_PCIDevice,AMT_PETCapabilities,AMT_PETFilterForTarget,AMT_PETFilterSetting,AMT_ProvisioningCertificateHash,AMT_PublicKeyCertificate,AMT_PublicKeyManagementCapabilities,AMT_PublicKeyManagementService,AMT_PublicPrivateKeyPair,AMT_RedirectionService,AMT_RemoteAccessCapabilities,AMT_RemoteAccessCredentialContext,AMT_RemoteAccessPolicyAppliesToMPS,AMT_RemoteAccessPolicyRule,AMT_RemoteAccessService,AMT_SetupAndConfigurationService,AMT_SNMPEventSubscriber,AMT_StateTransitionCondition,AMT_SystemDefensePolicy,AMT_SystemDefensePolicyInService,AMT_SystemDefenseService,AMT_SystemPowerScheme,AMT_ThirdPartyDataStorageAdministrationService,AMT_ThirdPartyDataStorageService,AMT_TimeSynchronizationService,AMT_TLSCredentialContext,AMT_TLSProtocolEndpoint,AMT_TLSProtocolEndpointCollection,AMT_TLSSettingData,AMT_TrapTargetForService,AMT_UserInitiatedConnectionService,AMT_WebUIService,AMT_WiFiPortConfigurationService,CIM_AbstractIndicationSubscription,CIM_Account,CIM_AccountManagementCapabilities,CIM_AccountManagementService,CIM_AccountOnSystem,CIM_AdminDomain,CIM_AlertIndication,CIM_AssignedIdentity,CIM_AssociatedPowerManagementService,CIM_AuthenticationService,CIM_AuthorizationService,CIM_Battery,CIM_BIOSElement,CIM_BIOSFeature,CIM_BIOSFeatureBIOSElements,CIM_BootConfigSetting,CIM_BootService,CIM_BootSettingData,CIM_BootSourceSetting,CIM_Capabilities,CIM_Card,CIM_Chassis,CIM_Chip,CIM_Collection,CIM_Component,CIM_ComputerSystem,CIM_ComputerSystemPackage,CIM_ConcreteComponent,CIM_ConcreteDependency,CIM_Controller,CIM_CoolingDevice,CIM_Credential,CIM_CredentialContext,CIM_CredentialManagementService,CIM_Dependency,CIM_DeviceSAPImplementation,CIM_ElementCapabilities,CIM_ElementConformsToProfile,CIM_ElementLocation,CIM_ElementSettingData,CIM_ElementSoftwareIdentity,CIM_ElementStatisticalData,CIM_EnabledLogicalElement,CIM_EnabledLogicalElementCapabilities,CIM_EthernetPort,CIM_Fan,CIM_FilterCollection,CIM_FilterCollectionSubscription,CIM_HostedAccessPoint,CIM_HostedDependency,CIM_HostedService,CIM_Identity,CIM_IEEE8021xCapabilities,CIM_IEEE8021xSettings,CIM_Indication,CIM_IndicationService,CIM_InstalledSoftwareIdentity,CIM_KVMRedirectionSAP,CIM_LANEndpoint,CIM_ListenerDestination,CIM_ListenerDestinationWSManagement,CIM_Location,CIM_Log,CIM_LogEntry,CIM_LogicalDevice,CIM_LogicalElement,CIM_LogicalPort,CIM_LogicalPortCapabilities,CIM_LogManagesRecord,CIM_ManagedCredential,CIM_ManagedElement,CIM_ManagedSystemElement,CIM_MediaAccessDevice,CIM_MemberOfCollection,CIM_Memory,CIM_MessageLog,CIM_NetworkPort,CIM_NetworkPortCapabilities,CIM_NetworkPortConfigurationService,CIM_OrderedComponent,CIM_OwningCollectionElement,CIM_OwningJobElement,CIM_PCIController,CIM_PhysicalComponent,CIM_PhysicalElement,CIM_PhysicalElementLocation,CIM_PhysicalFrame,CIM_PhysicalMemory,CIM_PhysicalPackage,CIM_Policy,CIM_PolicyAction,CIM_PolicyCondition,CIM_PolicyInSystem,CIM_PolicyRule,CIM_PolicyRuleInSystem,CIM_PolicySet,CIM_PolicySetAppliesToElement,CIM_PolicySetInSystem,CIM_PowerManagementCapabilities,CIM_PowerManagementService,CIM_PowerSupply,CIM_Privilege,CIM_PrivilegeManagementCapabilities,CIM_PrivilegeManagementService,CIM_ProcessIndication,CIM_Processor,CIM_ProtocolEndpoint,CIM_ProvidesServiceToElement,CIM_Realizes,CIM_RecordForLog,CIM_RecordLog,CIM_RedirectionService,CIM_ReferencedProfile,CIM_RegisteredProfile,CIM_RemoteAccessAvailableToElement,CIM_RemoteIdentity,CIM_RemotePort,CIM_RemoteServiceAccessPoint,CIM_Role,CIM_RoleBasedAuthorizationService,CIM_RoleBasedManagementCapabilities,CIM_RoleLimitedToTarget,CIM_SAPAvailableForElement,CIM_SecurityService,CIM_Sensor,CIM_Service,CIM_ServiceAccessBySAP,CIM_ServiceAccessPoint,CIM_ServiceAffectsElement,CIM_ServiceAvailableToElement,CIM_ServiceSAPDependency,CIM_ServiceServiceDependency,CIM_SettingData,CIM_SharedCredential,CIM_SoftwareElement,CIM_SoftwareFeature,CIM_SoftwareFeatureSoftwareElements,CIM_SoftwareIdentity,CIM_StatisticalData,CIM_StorageExtent,CIM_System,CIM_SystemBIOS,CIM_SystemComponent,CIM_SystemDevice,CIM_SystemPackaging,CIM_UseOfLog,CIM_Watchdog,CIM_WiFiEndpoint,CIM_WiFiEndpointCapabilities,CIM_WiFiEndpointSettings,CIM_WiFiPort,CIM_WiFiPortCapabilities,IPS_AdminProvisioningRecord,IPS_ClientProvisioningRecord,IPS_HostBasedSetupService,IPS_HostIPSettings,IPS_HTTPProxyService,IPS_HTTPProxyAccessPoint,IPS_IderSessionUsingPort,IPS_IPv6PortSettings,IPS_KVMRedirectionSettingData,IPS_KvmSessionUsingPort,IPS_ManualProvisioningRecord,IPS_OptInService,IPS_PowerManagementService,IPS_ProvisioningAuditRecord,IPS_ProvisioningRecordLog,IPS_RasSessionUsingPort,IPS_ScreenConfigurationService,IPS_ScreenSettingData,IPS_SecIOService,IPS_SessionUsingPort,IPS_SolSessionUsingPort,IPS_TLSProvisioningRecord,IPS_WatchDogAction'.split(',');
// ###END###{WsmanBrowser}
        var disconnecturl = null;
// ###BEGIN###{Terminal}
        var terminal;
// ###END###{Terminal}
        var currentView = 0;
        var LoadingHtml = '<div style=text-align:center;padding-top:20px>' + "Loading..." + '<div>';
        var amtversion = 0;
        var amtversionmin = 0;
        var amtFirstPull = 0; // Bitmask, Set this when the first pull request is made on a device: 1 = HardwareInfo, 2 = WirelessInfo, 4 = SystemDefense, 8 = Storage, 16 = EventLog, 32 = AuditLog, 64 = ExtraInfo, 128 = 802.1x
// ###BEGIN###{NetworkSettings}
        var amtwirelessif = -1; // Set to the interface index for the wireless interface, -1 if no wireless.
// ###END###{NetworkSettings}
// ###BEGIN###{Desktop}
        var desktop;
        var desktopsettings = { encflags: 1, showfocus: false, showmouse: true, showcad: true, limitFrameRate: false, noMouseRotate: false, decimationMode: 2 };
// ###END###{Desktop}
// ###BEGIN###{Mode-MeshCentral2}
        var currentMeshNode = null;
// ###END###{Mode-MeshCentral2}
        var webcompilerfeatures = [/*###WEBCOMPILERFEATURES###*/];
        var StatusStrs = ["Disconnected", "Connecting...", "Setup...", "Connected"];
// ###BEGIN###{Scripting}
        var scriptstate;
// ###END###{Scripting}
// ###BEGIN###{USBSetup}
        var setupbin;
        var selectedRecord = 0;
        var selectedVariable = 0;
// ###END###{USBSetup}
// ###BEGIN###{!Mode-MeshCentral2}
        var amtPowerPollTimer = null;
// ###END###{!Mode-MeshCentral2}
// ###BEGIN###{Mode-LMS}
        var lms = null;
        // ###END###{Mode-LMS}
        // ###BEGIN###{ComputerSelector-Local}
            // ###BEGIN###{Mode-NodeWebkit}
            var kerberos;
            try { kerberos = require('krb-ticket'); } catch (e) { console.log("Unable to setup kerberos"); }
            if (!kerberos || kerberos.initialize() != 0) { kerberos = null; }
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            var kerberos = null;
            // ###END###{!Mode-NodeWebkit}
            var filterFocus = false;
        // ###END###{ComputerSelector-Local}
        var t, t2, rsepass = null; // Global temporary variable
        // ###BEGIN###{MeshServerConnect}
        var meshCentralServer = null;
        // ###END###{MeshServerConnect}
        // ###BEGIN###{PowerControl-Advanced}
        // ###BEGIN###{PowerControl-OneClick}
        var webserver = null;
        // ###END###{PowerControl-OneClick}
        // ###END###{PowerControl-Advanced}
        // ###BEGIN###{DesktopClipboard}
        var xxKvmClipEnc = null;
        var xxKvmClipVal = null;
        // ###END###{DesktopClipboard}

        function startup() {
            // This is a bit freeky, but all HTML input elements are just going to be accessible directly.
            var allelements = document.getElementsByTagName('input');
            for (t = 0; t < allelements.length; t++) { if (allelements[t].id) { window[allelements[t].id] = allelements[t]; } }

            // ###BEGIN###{!Mode-NodeWebkit}
            urlvars = getUrlVars();
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}

            // Move things around to make space for the left-side toolbar
            QS('id_computerSelector').left = '52px';
            QS('id_computerListParent').left = '52px';
            QS('id_certManagerPanel').left = '52px';
            QS('id_certManagerPanel2').left = '52px';
            QS('id_usbSetupPanel').left = '52px';
            QS('id_usbSetupPanel2').left = '52px';
            // ###BEGIN###{SessionRecording}
            QS('id_sessionPlayerPanel').left = '52px';
            // ###END###{SessionRecording}

            // Parse the runtime arguments
            urlvars = getUrlVars();
            var argv = require('nw.gui').App.argv;
            for (var i in argv) {
                if (argv[i].substring(0,1) == '-') {
                    var j = argv[i].indexOf(':');
                    if (j == -1) {
                        urlvars[argv[i].substring(1)] = 1;
                    } else {
                        urlvars[argv[i].substring(1, j)] = argv[i].substring(j + 1);
                    }
                }
            }

            // If we are in NodeWebkit, check if we need to start a output log.
            if (urlvars.logfile && (typeof urlvars.logfile == 'string')) {
                g_logFile = require('fs').createWriteStream(urlvars.logfile, { flags: 'a' }); // Or 'w' to truncate the file every time the process starts.
                g_logStdout = process.stdout;
                console.logEx = console.log;
                console.log = function () {
                    if (arguments.length == 1) console.logEx(arguments[0]);
                    if (arguments.length == 2) console.logEx(arguments[0], arguments[1]);
                    if (arguments.length == 3) console.logEx(arguments[0], arguments[1], arguments[2]);
                    if (arguments.length == 4) console.logEx(arguments[0], arguments[1], arguments[2], arguments[3]);
                    if (arguments.length == 5) console.logEx(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
                    if (arguments.length == 6) console.logEx(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
                    if (arguments.length == 7) console.logEx(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]);
                    if (arguments.length == 8) console.logEx(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]);
                    g_logFile.write(require('util').format.apply(null, arguments) + '\r\n');
                    //g_logStdout.write(require('util').format.apply(null, arguments) + '\r\n'); //console.errorEx(arguments);
                }
                console.errorEx = console.error;
                console.error = console.log;
                console.log('--- LOG START: ' + new Date() + ' ---');
            }

            // If we are in NodeWebkit, check if we need to display the console window
            if (urlvars['debug'] == 1) { require('nw.gui').Window.get().showDevTools(); }

            // Prepend 'script' and 'list' with working directory if set and ':' is not in the string. This covers the case where self-extracting Commander has working directory set incorrectly.
            if (urlvars['script'] && (urlvars['script'].indexOf(':') < 0)) { urlvars['script'] = require('path').dirname(process.execPath) + '\\' + urlvars['script']; }
            if (urlvars['list'] && (urlvars['list'].indexOf(':') < 0)) { urlvars['list'] = require('path').dirname(process.execPath) + '\\' + urlvars['list']; }

            // Setup the TLS security mode
            try {
                NW_TlsSecurityMode = parseInt(localStorage.getItem('TlsSecurityMode') ? localStorage.getItem('TlsSecurityMode') : '1');
                NW_SkipTlsHostnameCheck = parseInt(localStorage.getItem('SkipTlsHostnameCheck') ? localStorage.getItem('SkipTlsHostnameCheck') : '0');
            } catch (ex) {
                NW_TlsSecurityMode = '1';
                NW_SkipTlsHostnameCheck = '0';
            }
            if (urlvars['tlssecurity']) { NW_TlsSecurityMode = parseInt(urlvars['tlssecurity']); }
            if (urlvars['ignoretls']) { NW_TlsSecurityMode = 0; }
            if (urlvars['skiptlshostcheck']) { NW_SkipTlsHostnameCheck = parseInt(urlvars['skiptlshostcheck']); }
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{DesktopClipboard}
            if (urlvars['kvmclip']) { QV('id_DeskKvmClipButton', true); }
            // ###END###{DesktopClipboard}

            // ###BEGIN###{ContextMenus}
            document.onclick = function (e) { hideContextMenu(); }
            // ###END###{ContextMenus}

            // ###BEGIN###{SessionRecording}
            srec_cleanup();
            Q('srec_PlaySpeed').value = 1;
            // ###END###{SessionRecording}

            // ###BEGIN###{Mode-LMS}
            // Setup LMS
            lms = CreateLmsControl();
            lms.onStateChanged = lmsChangedState;
            lms.onData = lmsOnData;
            lms.Start();
            QH('id_lmsData', LoadingHtml);
            QH('id_lmsData', '');
            QH('id_computername', 'Configuration Console v' + version);
            go(101);
            lmsRefresh();
            // ###END###{Mode-LMS}

            // ###BEGIN###{WsmanBrowser}
            // Add all WSMAN objects to WSMAN browser
            for (var w in AllWsman) { var option = document.createElement('option'); option.text = AllWsman[w]; option.id = 'WSB-' + AllWsman[w]; Q('id_QuerySelect').add(option); }
            // ###END###{WsmanBrowser}

            // ###BEGIN###{Desktop}
            // Setup the remote desktop
            desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk', Q('id_mainarea')));
            desktop.onStateChanged = onDesktopStateChange;
            QE('idx_connectbutton1', true);
            try { t = localStorage.getItem('desktopsettings'); } catch (ex) {}
            if (t) { desktopsettings = JSON.parse(t); }
            if (urlvars.kvmenc) { var v = parseInt(urlvars.kvmenc); if (typeof v == 'number') { desktopsettings.encflags = v; } }
            if (urlvars.kvmdec) { var v = parseInt(urlvars.kvmdec); if (typeof v == 'number') { desktopsettings.decimationMode = v; } }
            applyDesktopSettings();
            var s = '';
            //for (var c = 1; c < 13; c++) s += '<option value="' + (0xffbd + c) + '">F' + c +;
            //QH('specialkeylist', s);
            // ###END###{Desktop}

            // ###BEGIN###{Terminal}
            // Setup the terminal
            terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term'));
            terminal.onStateChanged = onTerminalStateChange;
            // ###BEGIN###{Terminal-Enumation-All}
            Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
            // ###END###{Terminal-Enumation-All}
            Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n')?"CR+LF":"LF";

            QE('idx_connectbutton2', true);

            // Setup Terminal drag & drop
            Q('p13').addEventListener('dragover', haltEvent, false);
            Q('p13').addEventListener('dragleave', haltEvent, false);
            Q('p13').addEventListener('drop', terminal_FileSelectHandler, false);
            // ###END###{Terminal}

            // Main drag & drop
            document.addEventListener('dragover', haltEvent, false);
            document.addEventListener('dragleave', haltEvent, false);
            document.addEventListener('drop', documentFileSelectHandler, false);

            // ###BEGIN###{Certificates}
            // Setup Terminal drag & drop
            Q('p16').addEventListener('dragover', haltEvent, false);
            Q('p16').addEventListener('dragleave', haltEvent, false);
            Q('p16').addEventListener('drop', cert_FileSelectHandler, false);
            // ###END###{Certificates}

            // ###BEGIN###{CertificateManager}
            // Setup Certificate Manager drag & drop
            Q('id_certManagerPanel').addEventListener('dragover', haltEvent, false);
            Q('id_certManagerPanel').addEventListener('dragleave', haltEvent, false);
            Q('id_certManagerPanel').addEventListener('drop', cert_importCertOk2, false);
            // ###END###{CertificateManager}

            // ###BEGIN###{CertificateManager}
            cert_loadCertificates();
            cert_updateCertificateList();
            // ###END###{CertificateManager}

            // ###BEGIN###{FileSaver}
            // ###BEGIN###{Desktop}
            // ###BEGIN###{!Mode-NodeWebkit}
            if (!Q('Desk')['toBlob']) { QV('idx_deskSaveBtn', false); }// On some browsers like IE, we can't save screen shots. Hide the sceeenshot/capture buttons.
            // ###END###{!Mode-NodeWebkit}
            // ###END###{Desktop}
            // ###END###{FileSaver}

            // ###BEGIN###{ComputerSelector}

            if (!urlvars['host']) { go(101); }
            QH('id_computername', format("Remote Management Console v{0}", version));

            // ###BEGIN###{ComputerSelector-Local}
            if (urlvars['host']) {
                // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                // If host is set to a hostname, connect directly to that computer
                var xuser = urlvars['user'];
                if (!xuser) xuser = '*'; // If user not set, default to * and use Kerberos
                var xpass = urlvars['pass'];
                if (!xpass) xpass = ''; // If password not set, default to blank.
                var xtls = 0;
                if (urlvars['tls'] == 1) { xtls = 1; }

                currentcomputer = { 'host': urlvars['host'], 'host': urlvars['host'], 'user': xuser, 'pass': xpass, 'tls': xtls, 'h': Math.random() };
                // ###BEGIN###{Mode-NodeWebkit}
                currentcomputer['tlscerthash'] = getCertPinning(urlvars['host']); // If we have a pinned TLS cert, add it here.
                // ###END###{Mode-NodeWebkit}
                disconnecturl = urlvars['disconnecturl'];
                if (!disconnecturl) disconnecturl = 'none';
                if (disconnecturl == 'none') QV('disconnectButton', false);
                if (disconnecturl == 'close') Q('disconnectButton').value = 'Close';
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
                if ((currentcomputer['user'] == '*') || (currentcomputer['pass'] != '')) {
                    // Don't prompt the user for password, just connect. This is Kerberos or password already provided.
                    connect(ports.host, ports.http, currentcomputer['user'], currentcomputer['pass'], currentcomputer['tls']);
                } else {
                    // Prompt the user for digest password.
                    computerlist = [currentcomputer];
                    updateComputerList();
                    computerConnect(null, currentcomputer.h);
                }

                // ###END###{!ComputerSelector-Local-ScriptOnly}
                // ###BEGIN###{ComputerSelector-Local-ScriptOnly}
                updateComputerList();
                // ###END###{ComputerSelector-Local-ScriptOnly}
            }
                // ###BEGIN###{!Mode-NodeWebkit}
            else if (urlvars['connect']) { loadServerComputer(); }
                // ###END###{!Mode-NodeWebkit}
            else {
                // ###BEGIN###{Mode-NodeWebkit}
                if (urlvars['list']) {
                    // Read the computers from a file list
                    var listok = 0;
                    try {
                        var ctext = require('fs').readFileSync(urlvars['list'], 'utf8');
                        if ((ctext.length > 2) && (ctext.charCodeAt(0) == 65533) && (ctext.charCodeAt(1) == 65533)) { // This is unicode detection
                            ctext = require('fs').readFileSync(urlvars['list'], 'utf16le');
                            if ((ctext.length > 1) && (ctext.charCodeAt(0) == 65279)) { ctext = ctext.substring(1); }
                        }
                        if (ctext) {
                            computerlist = JSON.parse(ctext);
                            if (computerlist.computers) { computerlist = computerlist.computers; }
                            var pins = getCertPinnings();
                            for (var i in computerlist) {
                                computerlist[i].checked = false;
                                if (!computerlist[i]['h']) computerlist[i]['h'] = Math.random(); // If 'h' handle is not present, create one.
                                if (!computerlist[i]['tls']) computerlist[i]['tls'] = 0; // If TLS is not present, assume 0.
                                if (!computerlist[i]['host'] && computerlist[i]['fqdn']) computerlist[i]['host'] = computerlist[i]['fqdn'];
                                if (!computerlist[i]['pass'] == null) computerlist[i]['pass'] = '';
                                if (computerlist[i]['fqdn']) delete computerlist[i]['fqdn'];

                                // Add stored certificate pinning.
                                if ((computerlist[i]['tlscerthash'] == null) && (pins[computerlist[i]['host']] != null)) { computerlist[i]['tlscerthash'] = pins[computerlist[i]['host']]; }
                                delete computerlist[i]['tlscert2'];
                                delete computerlist[i]['tlscerthash2'];
                            }
                            listok = computerlist.length;
                            if (listok > 0) updateComputerList();
                        }
                    } catch (e) { messagebox("Computer List", "Invalid list file: " + e) }
                    // Run a script on all computers
                    if (urlvars['script'] && listok > 0) {
                        // Select all computers
                        for (var i in computerlist) { Q('SJ-' + computerlist[i]['h']).checked = true; }
                        // Run the script
                        try {
                            var data = require('fs').readFileSync(urlvars['script'], 'utf8');
                            if (data) { mscript_onScriptRead( { target: { result: data }}, 1 ); }
                        } catch (e) { messagebox("Run Script", "Invalid script file.") }
                    }
                } else {
                    // Setup the computer selector
                    loadComputers();
                }
                // ###END###{Mode-NodeWebkit}
                // ###BEGIN###{!Mode-NodeWebkit}
                // Setup the computer selector
                loadComputers();
                // ###END###{!Mode-NodeWebkit}
            }
            // ###END###{ComputerSelector-Local}

            // ###BEGIN###{ComputerSelector-Remote}
            // Load the list of computers from the server
            loadServerComputerList();
            // ###END###{ComputerSelector-Remote}

            // ###END###{ComputerSelector}

            // ###BEGIN###{Mode-Firmware}
            connect('/wsman');
            // ###END###{Mode-Firmware}

            // ###BEGIN###{USBSetup}
            usb_displaySetupBin();

            // Add all possible variable types to dialog 16
            var options = '';
            for (var i in AmtSetupBinVarIds) { for (var j in AmtSetupBinVarIds[i]) { options += '<option value="' + i + '-' + j + '">' + AmtSetupBinVarIds[i][j][1] } }
            QH('d16type', options);
            // ###END###{USBSetup}

            document.onkeyup = handleKeyUp;
            document.onkeydown = handleKeyDown;
            document.onkeypress = handleKeyPress;
            window.onresize = center;
            center();

            // ###BEGIN###{Mode-NodeWebkit}
            NW_WindowTitle = require('nw.gui').Window.get().title;
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{Scripting-Editor}
            // ###BEGIN###{!Mode-Firmware}
            scriptLoadStartingBlocks();
            // ###END###{!Mode-Firmware}
            // ###END###{Scripting-Editor}

            // ###BEGIN###{Mode-NodeWebkit}
            NW_AutoUpdateCheck();
            // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
            if (urlvars['help'] || urlvars['?']) { messagebox("Commander Line Options", '<div style=text-align:left><b>-host:[hostname]</b>, ' + "Hostname or IP of Intel&reg; AMT" + '<br/><b>-user:[username]</b>, ' + "Digest login username" + '<br/><b>-pass:[password]</b>, ' + "Digest login password" + '<br/><b>-tls</b>, ' + "Connect using TLS security" + '<br/><b>-kvm</b>, ' + "Once connected go to remote desktop" + '<br/><b>-kvmfull</b>, ' + "Once connected go to fullscreen remote desktop" + '<br/><b>-kvmonly</b>, ' + "Perform fullscreen remote desktop only" + '<br/><b>-sol</b>, ' + "Once connected go to terminal" + '<br/><b>-script:[file]</b>, ' + "Run a script" + '<br/><b>-autoexit</b>, ' + "Exit after script is done" + '<br/><b>-ignoretls</b>, ' + "Don't check Intel&reg; AMT TLS certificate" + '<br/></div>'); }
            // ###END###{!ComputerSelector-Local-ScriptOnly}
            // ###BEGIN###{ComputerSelector-Local-ScriptOnly}
            if (urlvars['help'] || urlvars['?']) { messagebox("Commander Line Options", '<div style=text-align:left><b>-list:[listfile]</b>, ' + "List of computers to run a script on" + '<br/><b>-script:[file]</b>, ' + "Run a script" + '<br/><b>-autoexit</b>, ' + "Exit after all scripts are done" + '<br/><b>-ignoretls</b>, ' + "Don't check Intel&reg; AMT TLS certificate" + '<br/></div>'); }
            // ###END###{ComputerSelector-Local-ScriptOnly}
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{DesktopInbandFiles}
            // Setup upload drag & drop
            Q('p24filetable').addEventListener('drop', p24fileDragDrop, false);
            Q('p24filetable').addEventListener('dragover', p24fileDragOver, false);
            Q('p24filetable').addEventListener('dragleave', p24fileDragLeave, false);
            // ###END###{DesktopInbandFiles}

            // ###BEGIN###{DesktopRecorder}
            if (urlvars && urlvars['norecord']) { QV('id_DeskRecorderTools', false); }
            // ###END###{DesktopRecorder}

            // ###BEGIN###{Mode-NodeWebkit}
            // Check input arguments
            if (urlvars['webcn'] == 1) { delete urlvars['webcn']; setTimeout(function() { alert('Invalid webcn argument, use -webcn:domain.com.'); }, 100); }
            // ###END###{Mode-NodeWebkit}
        }

        // ###BEGIN###{PowerControl-Advanced}
        // ###BEGIN###{PowerControl-OneClick}
        function setupWebServer(leafCN) {
            if ((webserver != null) && (webserver.certCommonName == leafCN)) return;

            // Stop the web server if present
            if (webserver != null) { webserver.stop(); webserver = null; }

            // Create a web server to serve One Client Recovery (OCR) disk image files.
            webserver = CreateWebServer();
            webserver.generateCertificate(leafCN);
            webserver.start();
            webserver.onTransfers = function (webserver, transfers) {
                var x = '';
                for (var i in transfers) { x += '<div style="width:350px;position:relative;padding:3px"><span style="position:absolute;padding:3px;font-weight:bold">' + transfers[i].xfilename + '</span><div style="height:20px;background-color:#4CAF50;width:' + Math.floor((transfers[i].progress.count * 100) / transfers[i].xsize) + '%;border-radius:4px"></div></div>'; }
                QV('TransferNotification', transfers.length > 0);
                QH('TransferNotification', x);
            }

            //console.log('WebServer Cert Hash RAW', webserver.certHashRaw);
            //console.log('WebServer Cert Hash HEX', webserver.certHashHex);
        }
        // ###END###{PowerControl-OneClick}
        // ###END###{PowerControl-Advanced}

        function documentFileSelectHandler(e) {
            haltEvent(e);
            // ###BEGIN###{IDER}
            var diskimages = true;
            for (var i = 0; i < e.dataTransfer.files.length; i++) {
                if ((e.dataTransfer.files[i].name.toLowerCase().endsWith('.img') == false) && (e.dataTransfer.files[i].name.toLowerCase().endsWith('.iso') == false)) { diskimages = false; }
            }
            if ((diskimages == true) && (e.dataTransfer != null) && (currentView > 0) && (currentView < 100) && ((e.dataTransfer.files.length == 1) || (e.dataTransfer.files.length == 2))) {
                var floppyfile = null, cdromfile = null;
                if (e.dataTransfer.files[0].name.toLowerCase().endsWith('.iso')) { cdromfile = e.dataTransfer.files[0]; }
                if (e.dataTransfer.files[0].name.toLowerCase().endsWith('.img')) { floppyfile = e.dataTransfer.files[0]; }
                if (e.dataTransfer.files.length == 2) {
                    if (e.dataTransfer.files[1].name.toLowerCase().endsWith('.iso')) { cdromfile = e.dataTransfer.files[1]; }
                    if (e.dataTransfer.files[1].name.toLowerCase().endsWith('.img')) { floppyfile = e.dataTransfer.files[1]; }
                }
                if ((floppyfile != null) || (cdromfile != null)) iderStart3(floppyfile, cdromfile, 1);
                return;
            }
            // ###END###{IDER}

            if (e.dataTransfer == null || e.dataTransfer.files.length != 1) return;
            var f = null, filename = e.dataTransfer.files[0].name.toLowerCase();
            // ###BEGIN###{Storage}
            if (currentView == 21) { UploadToStorage(e.dataTransfer.files[0], filename); return; }
            // ###END###{Storage}
            // ###BEGIN###{ComputerSelector-Local}
            if (currentView == 101) {
                if (filename.endsWith('.mescript') || filename.endsWith('.meblocks')) { f = mscript_onScriptRead; }
                if (filename.endsWith('.json') || filename.endsWith('.csv')) { f = function (file) { onComputerListRead(file, filename); } }
            }
            // ###END###{ComputerSelector-Local}
            // ###BEGIN###{USBSetup}
            if (currentView == 102 && filename.endsWith('.bin')) { f = usb_onSetupBinRead; }
            // ###END###{USBSetup}
            // ###BEGIN###{Scripting}
            if (wsstack != null && (filename.endsWith('.mescript') || filename.endsWith('.meblocks'))) { f = script_onScriptRead; }
            // ###END###{Scripting}
            // ###BEGIN###{SessionRecording}
            if (currentView == 104 && filename.endsWith('.mcrec')) { srec_ondrop(e); return; }
            // ###END###{SessionRecording}
            if (f != null) { var reader = new FileReader(); reader.onload = f; reader.readAsBinaryString(e.dataTransfer.files[0]); }
        }

// ###BEGIN###{Mode-NodeWebkit}

        // ###BEGIN###{Look-Commander}
        function NW_CheckForUpdateMenu() {
            if (NW_UpdateMenuItem.checked == true) { NW_AutoUpdateCheck(); }
            try { localStorage.setItem('checkForUpdate', NW_UpdateMenuItem.checked); } catch (ex) { }
        }
        // ###END###{Look-Commander}

        // ###BEGIN###{Look-BrandedCommander}
        function NW_CheckForUpdateMenu() {
            if (NW_UpdateMenuItem.checked == true) { NW_AutoUpdateCheck(); }
            try { localStorage.setItem('checkForUpdate', NW_UpdateMenuItem.checked); } catch (ex) { }
        }
        // ###END###{Look-BrandedCommander}

        // Check if an update is available
        function NW_AutoUpdateCheck() {
            // ###BEGIN###{Look-Commander}
            // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
            try {
                if (localStorage.getItem('checkForUpdate') != 'false') {
                    var request = new XMLHttpRequest();
                    request.onload = function () {
                        if (request.status >= 200 && request.status < 400) {
                            var x = request.responseText, i = x.indexOf('##3B356F7A-0854-4EBA-B10D-4CC4FB522695##');
                            if (i > 0) {
                                x = x.substring(i);
                                var newversion = parseInt(x.substring(40, 46));
                                var criticalversion = parseInt(x.substring(48, 54));
                                var url = x.substring(56);
                                var j = url.indexOf('##');
                                if (j >= 0) {
                                    url = url.substring(0, j);
                                    var currentversion = version.split('.');
                                    currentversion = parseInt(currentversion[0] * 10000) + parseInt(currentversion[1] * 100) + parseInt(currentversion[2]);
                                    if (currentversion < newversion) {
                                        var newversiontext = Math.floor(newversion / 10000) + '.' + (Math.floor(newversion / 100) % 100) + '.' + (newversion % 100);
                                        var msg = format("MeshCommander v{0} is available", newversiontext);
                                        if (currentversion < criticalversion) {
                                            msg += ", it's a critical security update";
                                            QS('UpdateNotification')['background-color'] = 'orange';
                                        }
                                        QH('UpdateNotificationText', msg);
                                        QV('UpdateNotification', true);
                                    }
                                }
                            }
                        }
                    };
                    request.onerror = function () { console.log('Failed to get script blocks'); };
                    request.open('GET', 'https://sites.google.com/site/opensoftwareprojects/mesh/security-1/autoupdate', true);
                    request.send();
                }
            } catch (ex) { }
            // ###END###{!ComputerSelector-Local-ScriptOnly}
            // ###END###{Look-Commander}
            // ###BEGIN###{Look-BrandedCommander}
            try {
                if (localStorage.getItem('checkForUpdate') != 'false') {
                    var request = new XMLHttpRequest();
                    request.onload = function () {
                        if (request.status >= 200 && request.status < 400) {
                            var x = request.responseText, i = x.indexOf('##371cff53-32b7-4278-86c5-3e6906965332##');
                            if (i > 0) {
                                x = x.substring(i);
                                var newversion = parseInt(x.substring(40, 46));
                                var criticalversion = parseInt(x.substring(48, 54));
                                var url = x.substring(56);
                                var j = url.indexOf('##');
                                if (j >= 0) {
                                    url = url.substring(0, j);
                                    var currentversion = version.split('.');
                                    currentversion = parseInt(currentversion[0] * 10000) + parseInt(currentversion[1] * 100) + parseInt(currentversion[2]);
                                    if (currentversion < newversion) {
                                        var newversiontext = Math.floor(newversion / 10000) + '.' + (Math.floor(newversion / 100) % 100) + '.' + (newversion % 100);
                                        var msg = format("Intel&reg; Manageability Commander v{0} is available", newversiontext);
                                        if (currentversion < criticalversion) {
                                            msg += ", it's a critical security update";
                                            QS('UpdateNotification')['background-color'] = 'orange';
                                        }
                                        QH('UpdateNotificationText', msg);
                                        QV('UpdateNotification', true);
                                    }
                                }
                            }
                        }
                    };
                    request.onerror = function () { console.log('Failed to get script blocks'); };
                    request.open('GET', 'https://software.intel.com/en-us/articles/intel-manageability-commander', true);
                    request.send();
                }
            } catch (ex) { }
            // ###END###{Look-BrandedCommander}
        }

        function NW_HideUpdateNotification() {
            QV('UpdateNotification', false);
        }

        function NW_PerformUpdate() {
            require('nw.gui').Shell.openExternal('http://www.meshcommander.com/meshcommander');
        }

        var NW_WindowTitle = null;
        var NW_UpdateMenuItem = null;
        var NW_AmtScanMenuItem = null;
        var NW_TlsSecurityMode = 1;
        var NW_SkipTlsHostnameCheck = 0;

        function NW_SetupMainMenu(x) {
            var gui = require('nw.gui');
            var mainmenu = new gui.Menu({ type: 'menubar' });
            
            // Add Mac OS X specific menu
            var os = require('os');
            if (os.platform() == 'darwin') { mainmenu.createMacBuiltin('MeshCommander', { hideEdit: true, hideWindow: true }); }
            var filemenu = new gui.MenuItem({ label: "File" });
            var filemenusub = new gui.Menu();
            var seperator = false;
            var toolsmenu = null;
            var scriptmenu = null;
            var securitymenu = null;
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer == null) {
            // ###END###{MeshServerConnect}
            if (x == 101) {
                // Computer selector
                filemenusub.append(new gui.MenuItem({ label: "Add Intel AMT Computer...", click: addComputer }));
                filemenusub.append(new gui.MenuItem({ label: "Load Computers...", click: NW_LoadComputers }));
                filemenusub.append(new gui.MenuItem({ label: "Save Computers...", click: NW_SaveComputers }));
                // ###BEGIN###{ComputerSelectorScanner}
                filemenusub.append(new gui.MenuItem({ label: "Scan for Computers...", click: showScanDialog }));
                // ###END###{ComputerSelectorScanner}
                // ###BEGIN###{MeshServerConnect}
                filemenusub.append(new gui.MenuItem({ type: 'separator' }));
                filemenusub.append(new gui.MenuItem({ label: "Connect to MeshCentral...", click: showMeshCentralConnectDialog }));
                // ###END###{MeshServerConnect}
                seperator = true;
            }
            // ###BEGIN###{MeshServerConnect}
            } else {
                filemenusub.append(new gui.MenuItem({ label: "Disconnect from MeshCentral", click: meshCentralDisconnect }));
                seperator = true;
            }
            // ###END###{MeshServerConnect}
            // ###BEGIN###{USBSetup}
            if (x == 102) {
                // Setup.bin Editor
                filemenusub.append(new gui.MenuItem({ label: "New...", click: usb_newSetupBin }));
                filemenusub.append(new gui.MenuItem({ label: "Load Setup.bin...", click: NW_LoadSetupBin }));
                filemenusub.append(new gui.MenuItem({ label: "Save Setup.bin...", click: usb_saveSetupBin }));
                seperator = true;
            }
            // ###END###{USBSetup}

            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer == null) {
            // ###END###{MeshServerConnect}
            if (x >= 101 && x <= 104) {
                // Tools
                toolsmenu = new gui.MenuItem({ label: "Tools" });
                var toolsmenusub = new gui.Menu();
                toolsmenusub.append(new gui.MenuItem({ label: "Computer Management", click: NW_ComputerManagement, type: 'checkbox', checked: (x == 101) }));
                // ###BEGIN###{CertificateManager}
                toolsmenusub.append(new gui.MenuItem({ label: "Certificate Manager", click: NW_CertificateManager, type: 'checkbox', checked: (x == 103) }));
                // ###END###{CertificateManager}
                // ###BEGIN###{USBSetup}
                toolsmenusub.append(new gui.MenuItem({ label: "Setup.bin Manager", click: NW_SetupBinEditor, type: 'checkbox', checked: (x == 102) }));
                // ###END###{USBSetup}
                // ###BEGIN###{SessionRecording}
                toolsmenusub.append(new gui.MenuItem({ label: "Session Player", click: NW_SessionPlayer, type: 'checkbox', checked: (x == 104) }));
                // ###END###{SessionRecording}
                toolsmenu.submenu  = toolsmenusub;
            }
            // ###BEGIN###{Scripting}
            // ###BEGIN###{!Look-BrandedCommander}
            if (x == 101) {
                // Batch Scripting
                scriptmenu = new gui.MenuItem({ label: "Script" });
                var scriptmenusub = new gui.Menu();
                if (computersRunningScripts > 0) {
                    scriptmenusub.append(new gui.MenuItem({ label: "Stop All Scripts", click: mscript_runScriptDlg }));
                } else {
                    scriptmenusub.append(new gui.MenuItem({ label: "Start Script...", click: mscript_runScriptDlg }));
                }
                scriptmenu.submenu  = scriptmenusub;
            }
            if (x >= 0 && x < 100) {
                // Computer Scripting
                scriptmenu = new gui.MenuItem({ label: "Script" });
                var scriptmenusub = new gui.Menu();
                if (scriptstate) {
                    scriptmenusub.append(new gui.MenuItem({ label: "Stop Script", click: script_Stop }));
                } else {
                    scriptmenusub.append(new gui.MenuItem({ label: "Start Script...", click: script_runScriptDlg }));
                }
                scriptmenu.submenu  = scriptmenusub;
            }
            // ###END###{!Look-BrandedCommander}
            // ###END###{Scripting}

            if (x == 101) {
                // Security
                securitymenu = new gui.MenuItem({ label: "Security" });
                var securitymenusub = new gui.Menu();
                securitymenusub.append(new gui.MenuItem({ label: "Ignore TLS certificate", click: NW_ChangeTlsSecurityMode0, type: 'checkbox', checked: (NW_TlsSecurityMode == 0) }));
                securitymenusub.append(new gui.MenuItem({ label: "View TLS certificate && pin", click: NW_ChangeTlsSecurityMode1, type: 'checkbox', checked: (NW_TlsSecurityMode == 1) }));
                securitymenusub.append(new gui.MenuItem({ type: 'separator' }));
                NW_SkipTlsHostnameMenuItem = new gui.MenuItem({ label: "Skip TLS hostname check", click: NW_SkipTlsHostnameCheck0, type: 'checkbox', checked: (NW_SkipTlsHostnameCheck == 1) })
                securitymenusub.append(NW_SkipTlsHostnameMenuItem);
                securitymenu.submenu  = securitymenusub;
            }
            // ###BEGIN###{MeshServerConnect}
            }
            // ###END###{MeshServerConnect}

            if (x >= 0 && x < 100 && disconnecturl != 'none' && disconnecturl != 'close') {
                // Computer screen
                filemenusub.append(new gui.MenuItem({ label: "Disconnect", click: disconnect }));
                seperator = true;
            }
            
            // Explicit exit action not required on Mac. The MacBuiltin menu includes native option to quit application (Quit)
            if (os.platform() != 'darwin') {
                if (seperator == true) filemenusub.append(new gui.MenuItem({ type: 'separator' }));
                filemenusub.append(new gui.MenuItem({ label: "Exit", click: NW_Exit }));
            }

            filemenu.submenu  = filemenusub;
            if (x == 13) {
                // Terminal
                toolsmenu = new gui.MenuItem({ label: "Terminal" });
                var toolsmenusub = new gui.Menu();
                if (terminal.State == 0) {
                    toolsmenusub.append(new gui.MenuItem({ label: "Connect", click: connectTerminal }));
                } else {
                    toolsmenusub.append(new gui.MenuItem({ label: "Disconnect", click: connectTerminal }));
                }
                // ###BEGIN###{FileSaver}
                toolsmenusub.append(new gui.MenuItem({ type: 'separator' }));
                if (terminal.m.capture == null) {
                    // ###BEGIN###{!TerminalReplay}
                    toolsmenusub.append(new gui.MenuItem({ label: "Start Capture", click: terminalCaptureToggle }));
                    // ###END###{!TerminalReplay}
                    // ###BEGIN###{TerminalReplay}
                    if (terminalReplayTimer == null) {
                        toolsmenusub.append(new gui.MenuItem({ label: "Start Capture", click: terminalCaptureToggle }));
                        toolsmenusub.append(new gui.MenuItem({ label: "Replay Capture", click: terminalReplay }));
                    } else {
                        toolsmenusub.append(new gui.MenuItem({ label: "Stop Replay", click: terminalReplay }));
                    }
                    // ###END###{TerminalReplay}
                } else {
                    toolsmenusub.append(new gui.MenuItem({ label: "Stop Capture", click: terminalCaptureToggle }));
                }
                // ###END###{FileSaver}
                toolsmenu.submenu  = toolsmenusub;
            }
            if (x == 14) {
                // Desktop
                toolsmenu = new gui.MenuItem({ label: "Desktop" });
                var toolsmenusub = new gui.Menu();
                if (desktop.State == 0) {
                    toolsmenusub.append(new gui.MenuItem({ label: "Connect", click: connectDesktop }));
                } else {
                    toolsmenusub.append(new gui.MenuItem({ label: "Disconnect", click: connectDesktop }));
                }
                toolsmenusub.append(new gui.MenuItem({ type: 'separator' }));
                toolsmenusub.append(new gui.MenuItem({ label: "Settings", click: showDesktopSettings }));
                toolsmenu.submenu  = toolsmenusub;
            }

            // Language menu
            var languagemenu = new gui.MenuItem({ label: "Language" });
            var languagesubmenu = new gui.Menu();
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'en'), label: "English", click: function () { window.location.href = 'commander.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'zh-chs'), label: "Chinese (Simplified)", click: function () { window.location.href = 'commander_zh-chs.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'nl'), label: "Dutch", click: function () { window.location.href = 'commander_nl.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'fr'), label: "French", click: function () { window.location.href = 'commander_fr.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'de'), label: "German", click: function () { window.location.href = 'commander_de.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'it'), label: "Italian", click: function () { window.location.href = 'commander_it.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'ja'), label: "Japanese", click: function () { window.location.href = 'commander_ja.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'pt'), label: "Portuguese", click: function () { window.location.href = 'commander_pt.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'ru'), label: "Russian", click: function () { window.location.href = 'commander_ru.htm'; } }));
            languagesubmenu.append(new gui.MenuItem({ type: 'checkbox', checked: (document.documentElement.lang == 'es'), label: "Spanish", click: function () { window.location.href = 'commander_es.htm'; } }));
            languagemenu.submenu = languagesubmenu;

            var helpmenu = new gui.MenuItem({ label: "Help" });
            var helpmenusub = new gui.Menu();
            // ###BEGIN###{Look-Commander}
            var checkForUpdateCheck = false;
            try { checkForUpdateCheck = (localStorage.getItem('checkForUpdate') == 'false') ? false : true; } catch (ex) {}
            NW_UpdateMenuItem = new gui.MenuItem({ type: 'checkbox', checked: checkForUpdateCheck, label: "Check for updates", click: NW_CheckForUpdateMenu })
            helpmenusub.append(NW_UpdateMenuItem);
            // ###END###{Look-Commander}
            // ###BEGIN###{Look-BrandedCommander}
            var checkForUpdateCheck = false;
            try { checkForUpdateCheck = (localStorage.getItem('checkForUpdate') == 'false') ? false : true; } catch (ex) { }
            NW_UpdateMenuItem = new gui.MenuItem({ type: 'checkbox', checked: checkForUpdateCheck, label: "Check for updates", click: NW_CheckForUpdateMenu })
            helpmenusub.append(NW_UpdateMenuItem);
            // ###END###{Look-BrandedCommander}
            // ###BEGIN###{ComputerSelectorScanner}
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer == null) {
            // ###END###{MeshServerConnect}
            var amtPresenceScan = true;
            try { amtPresenceScan = (localStorage.getItem('scanForComputers') == 'false') ? false : true; } catch (ex) { }
            NW_AmtScanMenuItem = new gui.MenuItem({ type: 'checkbox', checked: amtPresenceScan, label: "Scan for presence", click: NW_AmtScanMenu })
            helpmenusub.append(NW_AmtScanMenuItem);
            if (amtPresenceScan == true) { globalAmtScanner.start(); }
            // ###BEGIN###{MeshServerConnect}
            }
            // ###END###{MeshServerConnect}
            // ###END###{ComputerSelectorScanner}
            helpmenusub.append(new gui.MenuItem({ label: "Reset", click: NW_Reload }));
            if (urlvars['debug']) { helpmenusub.append(new gui.MenuItem({ label: "Show Debug...", click: NW_Debug })); }
            // ###BEGIN###{Look-ISDU}
            helpmenusub.append(new gui.MenuItem({ type: 'separator' }));
            helpmenusub.append(new gui.MenuItem({ label: "About...", click: WM_About }));
            // ###END###{Look-ISDU}
            // ###BEGIN###{Look-BrandedCommander}
            helpmenusub.append(new gui.MenuItem({ type: 'separator' }));
            helpmenusub.append(new gui.MenuItem({ label: "About...", click: WM_About }));
            // ###END###{Look-BrandedCommander}
            helpmenu.submenu  = helpmenusub;
            mainmenu.append(filemenu);
            if (toolsmenu != null) mainmenu.append(toolsmenu);
            if (scriptmenu != null) mainmenu.append(scriptmenu);
            if (securitymenu != null) mainmenu.append(securitymenu);
            mainmenu.append(languagemenu);
            mainmenu.append(helpmenu);
            gui.Window.get().menu = mainmenu;
        }

        function NW_Exit() {
            require('nw.gui').Window.get().close(); // Closes only the current window.
            //require('nw.gui').App.quit(); // Closes all instances of the app.
        }
        function NW_Reload() { require('nw.gui').Window.get().reloadIgnoringCache(); }
        function NW_Debug() { require('nw.gui').Window.get().showDevTools(); }

        function NW_ChangeTlsSecurityMode0() { NW_TlsSecurityMode = 0; try { localStorage.setItem('TlsSecurityMode', NW_TlsSecurityMode); } catch (ex) { } NW_SetupMainMenu(currentView); }
        function NW_ChangeTlsSecurityMode1() { NW_TlsSecurityMode = 1; try { localStorage.setItem('TlsSecurityMode', NW_TlsSecurityMode); } catch (ex) { } NW_SetupMainMenu(currentView); }
        function NW_SkipTlsHostnameCheck0() { NW_SkipTlsHostnameCheck = NW_SkipTlsHostnameMenuItem.checked ? 1 : 0; try { localStorage.setItem('SkipTlsHostnameCheck', NW_SkipTlsHostnameCheck); } catch (ex) { } NW_SetupMainMenu(currentView); }
        function NW_LoadComputers() {
            var chooser = Q('idx_d17computerlistfile');
            if (chooser.getAttribute('eventset') != 1) {
                chooser.setAttribute('eventset', '1');
                chooser.addEventListener('change', NW_LoadComputersEx, false);
            }
            chooser.value = null;
            chooser.click();
        }
        function NW_LoadComputersEx(evt) {
            var reader = new FileReader();
            reader.onload = function(file) { onComputerListRead(file, Q('idx_d17computerlistfile').files[0].name); }
            reader.readAsBinaryString(this.files[0]);
        }

        function NW_SaveComputers() { saveComputerList(); }
        function NW_ComputerManagement() { toolmenuclick(-1); go(101); }
        // ###BEGIN###{CertificateManager}
        function NW_CertificateManager() { toolmenuclick(-1); go(103); }
        // ###END###{CertificateManager}
        function NW_SetupBinEditor() { toolmenuclick(-1); go(102); }
        // ###BEGIN###{SessionRecording}
        function NW_SessionPlayer() { toolmenuclick(-1); go(104); }
        // ###END###{SessionRecording}

        function NW_LoadSetupBin() {
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('accept', '.bin');
            chooser.addEventListener('change', NW_LoadSetupBinEx, false);
            chooser.value = null;
            chooser.click();
        }
        function NW_LoadSetupBinEx() {
            var reader = new FileReader();
            reader.onload = function(file) { usb_onSetupBinRead(file); }
            reader.readAsBinaryString(this.files[0]);
        }

        // ###BEGIN###{Look-ISDU}
        function WM_About() {
            var x = { 'position': 'center', 'focus': true, 'frame': true, 'icon': 'favicon.png', 'width': 520, 'height': 320 };
            if (process.version == 'v1.2.0') x['toolbar'] = false;
            require('nw.gui').Window.open('about.htm', x);
        }
        // ###END###{Look-ISDU}

        // ###BEGIN###{Look-BrandedCommander}
        function WM_About() {
            var x = { 'position': 'center', 'focus': true, 'frame': true, 'icon': 'favicon.png', 'width': 520, 'height': 320 };
            if (process.version == 'v1.2.0') x['toolbar'] = false;
            require('nw.gui').Window.open('about.htm', x);
        }
        // ###END###{Look-BrandedCommander}

// ###END###{Mode-NodeWebkit}

// ###BEGIN###{ComputerSelector}
        // Load the list of computers from the server
        function loadServerComputerList() {
            var request = new XMLHttpRequest();
            request.onload = function() {
                if (request.status >= 200 && request.status < 400) {
                    // Success
                    var serverComputerList = JSON.parse(request.responseText);
                    if (serverComputerList && serverComputerList != null && serverComputerList instanceof Array) {
                        currentcomputer = null;
                        computerlist = [];
                        for (var i in serverComputerList) {
                            var computer = serverComputerList[i];
                            if (computer['host']) {
                                computer.checked = false;
                                if (!computer['h']) computer['h'] = Math.random(); // If 'h' handle is not present, create one.
                                if (!computer['tls']) computer['tls'] = 0; // If TLS is not present, assume 0.
                                computerlist.push(computer);
                            }
                        }
                        updateComputerList();
                    }
                } else {
                    console.log('Failed to get server computer list');
                }
            };

            request.onerror = function() {
                console.log('Failed to get server computer list');
            };

            // ###BEGIN###{ComputerSelector-Remote}
            request.open('GET', 'webrelay.ashx?action=getcomputerlist', true);
            // ###END###{ComputerSelector-Remote}
            // ###BEGIN###{ComputerSelector-Local}
            request.open('GET', urlvars['connect'], true);
            // ###END###{ComputerSelector-Local}
            request.send();
        }
// ###END###{ComputerSelector}

// ###BEGIN###{Mode-LMS}
        // Called when the LMS control channel changes state
        function lmsChangedState(sender, state)
        {
            //console.log("LMS Control Channel State: " + state);
            if (state == 0) { 
                setDialogMode();
                QV('id_lmsToolBarContent', false);
                QH('id_lmsData', '<div style=text-align:center;padding-top:20px>' + "MicroLMS disconnected." + '<div>');
                QH('id_lmsData2', '');
            } else if (state == 2) { QV('id_lmsToolBarContent', true); lmsRefresh(); }
        }

        function lmsLogin() { window.location.href = '/authindex.html'; }

        var lmsProvisioningStates = ["Pre-Provisioning", "In-Provisioning", "Post-Provisioning"];
        var lmsProvisioningModes = ["None", "Enterprise Mode", "Small Buisness Mode", "Remote Assistance Mode"];
        var lmsMeInfo = null;
        var lmsTemp = null;
        var lmsNotifications = null;

        // Called when data is received on the LMS control channel
        function lmsOnData(sender, data)
        {
            var cmdid = ReadShortX(data, 0);
            //console.log("LMS Control Channel Data: " + data + ", cmdid:" + cmdid);

            switch (+cmdid) {
                case 1: { // ME Information
                    //console.log(data.substring(2));
                    var meinfo = JSON.parse(data.substring(2));
                    QV('id_lmsLoginButton', meinfo['LoginMode'] == 1);

                    // If Intel AMT is in-between states, reload data in a few seconds.
                    if ((meinfo['TrustedHashes'] != null) && (meinfo['ProvisioningMode'] == -858993460)) {
                        QV('id_lmsConfigureButton', false);
                        QV('id_lmsActivateButton', false);
                        QV('id_lmsDeactivateButton', false);
                        setTimeout(lmsRefresh, 1000);
                        return;
                    }

                    lmsMeInfo = meinfo;
                    if (meinfo['ProvisioningState'] == null) {
                        QH('id_lmsData', '<div style=text-align:center;padding-top:20px>' + "Intel&reg; AMT not found" + '<div>');
                        QH('id_lmsData2', '');
                    } else {
                        meinfo['Flags'] = +meinfo['Flags'];

                        var x = '<h2>' + "Current Status" + '</h2>';
                        x += TableStart();
                        if (meinfo['ProvisioningState'] != 2) {
                            x += TableEntry("Activation state", lmsProvisioningStates[meinfo['ProvisioningState']]);
                        } else {
                            if (meinfo['Flags'] & 2) { x += TableEntry("Activation state", "Activated in Client Control Mode"); }
                            else if (meinfo['Flags'] & 4) { x += TableEntry("Activation state", "Activated in Admin Control Mode"); }
                            else { x += TableEntry("Activation state", "Activated, " + lmsProvisioningModes[meinfo['ProvisioningMode']]); }
                        }
                        x += TableEntry("Intel&reg; AMT version", addLink(meinfo['Versions']['AMT'], 'lmsShowVersionsDlg()'));
                        if (meinfo['MeiVersion'] != null) { x += TableEntry("Intel&reg; MEI driver version", meinfo['MeiVersion']); }
                        x += TableEnd();

                        if (meinfo['ProvisioningState'] != 2) {
                            x += '<h2>' + "Activation Information" + '</h2>';
                            x += TableStart();
                            if (meinfo['DnsSuffix']) {
                                x += TableEntry("Trusted DNS suffix", meinfo['DnsSuffix']);
                            } else {
                                x += TableEntry("Trusted DNS suffix", '<i>' + "Not Set" + '</i>');
                            }
                            if (meinfo['TrustedHashes'] != null) {
                                if (meinfo['TrustedHashes'].length == 1) {
                                    x += TableEntry("Trusted hashes", addLink(meinfo['TrustedHashes'].length + ' hash', 'lmsShowTrustedHashesDlg()'));
                                } else {
                                    x += TableEntry("Trusted hashes", addLink(meinfo['TrustedHashes'].length + ' hashes', 'lmsShowTrustedHashesDlg()'));
                                }
                            }
                            x += TableEnd();
                        }

                        QH('id_lmsData', x);
                        QV('id_lmsData2', true);
                        lmsNotifications = meinfo['Notifications'].reverse();
                        lmsRefreshNotifications();
                        QV('id_lmsConfigureButton', (meinfo['ProvisioningState'] == 2)); // Only display the "Login..." button if Intel AMT is in post-provisioning state.
                        QV('id_lmsActivateButton', (meinfo['ProvisioningState'] == 0) && (meinfo['LoginMode'] >= 2)); // Only display the "Activate..." button if Intel AMT is in pre-provisioning state and we are adrministrator.
                        QV('id_lmsDeactivateButton', (meinfo['ProvisioningState'] == 2) && (meinfo['Flags'] & 2) && (meinfo['LoginMode'] >= 2)); // Only display the "Deactivate..." button if Intel AMT is in port-provisioning state & in client control mode & we are adrministrator.
                    }
                    break;
                }
                case 2: { // Intel ME Un-Provisioning
                    lmsDeactivateX2(ReadIntX(data, 2));
                    break;
                }
                case 3: { // Intel ME System Account Information
                    var status = ReadIntX(data, 2);
                    if (status != 0) {
                        messagebox("Intel&reg; AMT Activation", format("Failed to get account information, status {0}", status));
                    } else {
                        var meuser = data.substring(6, data.indexOf('\0', 6));
                        var mepass = data.substring(39, data.indexOf('\0', 39));
                        QH('id_dialogMessage', "Fetching activation status...");
                        wsstack = WsmanStackCreateService("localhost", 16992, meuser, mepass, false);
                        amtstack = AmtStackCreateService(wsstack);
                        amtstack.onProcessChanged = onProcessChanged;
                        amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], lmsActivationX1);
                    }
                    break;
                }
                case 9: { // New notification
                    var notification = JSON.parse(data.substring(2));
                    if (lmsNotifications == null) { lmsNotifications = []; }
                    lmsNotifications.unshift(notification);
                    lmsRefreshNotifications();
                    if ((notification.code == 'iAMT0055-0') || (notification.code == 'iAMT0055-1') || (notification.code == 'iAMT0055-2')) { setDialogMode(); lmsRefresh(); }
                    break;
                }
            }
        }

        function lmsRefreshNotifications() {
            var x = '<h2>' + "Notifications" + '</h2>' + TableStart();
            if (lmsNotifications && lmsNotifications.length > 0) {
                for (var i in lmsNotifications) {
                    var n = lmsNotifications[i], v = n.str;
                    if (n.code != 'iAMT0050-32') {
                        if (v.indexOf('User Notification Alert - ') == 0) { v = v.substring(26); }
                        x += TableEntry(new Date(n.date).toLocaleString(), v);
                    }
                }
            } else {
                x += '<tr><td style=padding:8px><i>' + "No notifications found." + '</i><td>';
            }
            x += TableEnd();
            QH('id_lmsData2', x);
        }

        function lmsActivationX1(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Intel&reg; AMT Activation", format("Failed to fetch activation status, status {0}", status));
            } else if (responses['IPS_HostBasedSetupService'].response['AllowedControlModes'].length != 2) {
                messagebox("Intel&reg; AMT Activation", "Client control mode activation not allowed");
            } else {
                lmsTemp = responses['AMT_GeneralSettings'].response;
                amtstack.IPS_HostBasedSetupService_Setup(2, rstr2hex(rstr_md5('admin:' + responses['AMT_GeneralSettings'].response['DigestRealm'] + ':' + d4password.value)), null, null, null, null, lmsActivationX2);
            }
        }

        function lmsActivationX2(stack, name, response, status) {
            if (status != 200 || response.Body['ReturnValue'] != 0) {
                messagebox("Intel&reg; AMT Activation", format("Failed activation, status {0}", status));
            } else {
                setDialogMode();
                lmsRefresh();
                lmsTemp['HostName'] = lmsMeInfo['OsHostname']; // Set the OS hostname
                // TODO: Also set the local FQDN if we can get it from LMS
                wsstack = WsmanStackCreateService('localhost', 16992, 'admin', d4password.value, false);
                amtstack = AmtStackCreateService(wsstack);
                amtstack.onProcessChanged = onProcessChanged;
                amtstack.Put('AMT_GeneralSettings', lmsTemp, function() { }, 0, 1);
            }
        }

        function lmsDeactivate() {
            if (xxdialogMode || lms.State != 2) return;
            QH('id_dialogMessage', "Confirm Intel&reg; AMT deactivation?");
            setDialogMode(1, "Intel&reg; AMT Deactivation", 3, lmsDeactivateX1);
        }

        function lmsDeactivateX1() {
            statusbox("Intel&reg; AMT Deactivation", "Deactivating Intel&reg; AMT...");
            lms.SendCmd(2, IntToStrX(1)); // Send request for deactivation
        }

        function lmsDeactivateX2(status) {
            if (status != 0) {
                messagebox("Intel&reg; AMT Deactivation", format("Failed deactivation, status ", status));
            } else {
                QH('id_lmsData', "Please wait for deactivation...");
                QV('id_lmsData2', false);
                setDialogMode();
                lmsRefresh();
            }
        }

        // Refresh button on the UI
        function lmsRefresh() {
            if (lms.State != 2) return;
            lms.SendCmd(1, ''); // Send the request basic information command
        }

        // Configure button on the UI
        function lmsConfigure() {
            if (xxdialogMode) return;
            setDialogMode(4, "Intel&reg; AMT Login", 3, function () { lmsConfigureLogin(); });
            //d4username.readOnly = false;
            d4username.disabled = false;
            if (d4username.value == 'admin') d4username.value = '';
            inputBoxFocus('d4username');
            lmsUpdateLoginDialog();
        }

        // Called when the user hits OK on the login dialog
        function lmsConfigureLogin() {
            var user = d4username.value;
            if (user == '') user = 'admin';
            connect('localhost', 16992, user, d4password.value, 0);
        }

        // Activate button on the UI
        function lmsActivate() {
            if (xxdialogMode|| lms.State != 2) return;
            setDialogMode(4, "Intel&reg; AMT Activation", 3, function () { lmsActivateEx(); });
            //d4username.readOnly = true;
            d4username.disabled = true;
            d4username.value = 'admin';
            inputBoxFocus('d4password');
            lmsUpdateLoginDialog();
        }

        // Go head with Intel AMT client control mode activation
        function lmsActivateEx()
        {
            lms.SendCmd(3); // Send request for account information
            statusbox("Intel&reg; AMT Activation", "Fetching Account Information...");
        }

        // Called each time something changes in the login dialog
        function lmsUpdateLoginDialog(e, d) {
            var ok = passwordcheck(d4password.value);
            QE('idx_dlgOkButton', ok);
            if (e != null && e.keyCode == 13 && d == 1) inputBoxFocus('d4password');
            if (ok == true && e != null && e.keyCode == 13 && d == 2) dialogclose(1);
        }

        var lmsHashArgStrings = ["MD5", "SHA1", "SHA256", "SHA512"];
        function lmsShowTrustedHashesDlg() {
            // {\"AC\":%d,\"DF\":%d,\"AL\":%d,\"NA\":\"%s\",\"HA\":\"%s\"}"

            var x = '<div style=max-height:240px;overflow-y:scroll>' + TableStart();
            for (var i in lmsMeInfo['TrustedHashes'])
            {
                //x += '<b>' + lmsMeInfo['TrustedHashes'][i]['Name'] + '</b><br><span style=font-size:10px>' + lmsHashArgStrings[lmsMeInfo['TrustedHashes'][i]['HashAlgorithm']] + (lmsMeInfo['TrustedHashes'][i]['Active'] == 1?", Active":'') + (lmsMeInfo['TrustedHashes'][i]['Default'] == 1?", Default":'') + '</span><br><span style=font-size:10px>' + lmsMeInfo['TrustedHashes'][i]['Hash'] + '</span><br><br>';
                x += TableEntry('<b>' + lmsMeInfo['TrustedHashes'][i]['Name'] + '</b><br><span style=font-size:10px>' + lmsHashArgStrings[lmsMeInfo['TrustedHashes'][i]['HashAlgorithm']] + (lmsMeInfo['TrustedHashes'][i]['Active'] == 1?", Active":'') + (lmsMeInfo['TrustedHashes'][i]['Default'] == 1?", Default":'') + '</span><br><span style=font-size:8px>' + lmsMeInfo['TrustedHashes'][i]['Hash'] + '</span>', '');
            }
            x += TableEnd() + '</div>';
            messagebox("Intel&reg; AMT Trusted Hashes", x);
        }

        function lmsShowVersionsDlg() {
            var x = TableStart();
            x += TableEntry("Intel&reg; AMT", lmsMeInfo['Versions']['AMT']);
            if (lmsMeInfo['MeiVersion'] != null) { x += TableEntry("Intel&reg; MEI driver", lmsMeInfo['MeiVersion']); }
            for (var i in lmsMeInfo['Versions']) { if (i != 'AMT') x += TableEntry(i, lmsMeInfo['Versions'][i]); }
            x += TableEnd();
            messagebox("Intel&reg; AMT Versions", x);
        }

// ###END###{Mode-LMS}

// ###BEGIN###{Mode-MeshCentral2}
        function connectButtonfunction() {
            if (!wsstack || wsstack.socketState == 0) { meshcentral2credCallback(); } else { disconnect(); }
        }

        function connectButtonfunctionEx() {
            currentMeshNode = parent.getCurrentNode();
            connect(currentMeshNode._id, 16992, null, null, 0);
            Q('xconnectbutton1').value = "Disconnect";
        }

        function getCurrentMeshNode() { return currentMeshNode; }
        function setConnectionState(isConnectable) { QE('xconnectbutton1', isConnectable); if (isConnectable == false) { disconnect(); } }
        function setFrameHeight(height) {
            //console.log('setFrameHeight', height);
            //QS('entireBody').height = height;
        }
        function setAuthCallback(updateAmtCredentials) { meshcentral2credCallback = updateAmtCredentials; }
        function setUrlVar(name, value) { if (!urlvars) { urlvars = {}; } urlvars[name] = value; }
// ###END###{Mode-MeshCentral2}

        function cleanup() {
            // ###BEGIN###{Terminal}
            // ###BEGIN###{FileSaver}
            // ###BEGIN###{!Mode-NodeWebkit}
            idx_terminalCaptureButton.value = "Start Capture";
            // ###END###{!Mode-NodeWebkit}
            if (terminal.m.capture) delete terminal.m.capture;
            // ###END###{FileSaver}
            terminal.Stop();
            // ###END###{Terminal}
            // ###BEGIN###{Desktop}
            desktop.disconnectCode = 0;
            desktop.Stop();
            // ###END###{Desktop}
        }

        function handleKeyUp(e) {
            if (xxdialogMode) return;
            // ###BEGIN###{ComputerSelector}
            // ###BEGIN###{ComputerSelector-Local}
            if (currentView == 101) {
                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer == null) {
                // ###END###{MeshServerConnect}
                    if (e.keyCode == 45) { addComputer(); } // Insert key
                    if (e.keyCode == 46) { deleteComputers(); } // Delete key
                // ###BEGIN###{MeshServerConnect}
                }
                // ###END###{MeshServerConnect}
                if ((e.keyCode == 65) && (e.ctrlKey == true)) { selectAllComputers(); } // Select all
                if (e.keyCode == 13) { if (computersRunningScripts == 0) { computerConnect(event, currentcomputer.h); } } // Enter key
                if ((e.keyCode == 8) && !filterFocus) { var x = Q('computerFilter').value; Q('computerFilter').value = (x.substring(0, x.length - 1)); computerFilterFunc(); }
                if (e.keyCode == 27) { Q('computerFilter').value = ''; computerFilterFunc(); }
            }
            // ###END###{ComputerSelector-Local}
            // ###BEGIN###{ComputerSelector-Remote}
            if (currentView == 101) {
                if ((e.keyCode == 65) && (e.ctrlKey == true)) { selectAllComputers(); } // Select all
            }
            // ###END###{ComputerSelector-Remote}
            // ###END###{ComputerSelector}
            // ###BEGIN###{CertificateManager}
            if (currentView == 103) {
                //if (e.keyCode == 45) { addComputer(); } // Insert key
                if (e.keyCode == 46) { cert_deleteCertificates(); } // Delete key
                //if ((e.keyCode == 65) && (e.ctrlKey == true)) { selectAllCertificates(); } // Select all
            }
            // ###END###{CertificateManager}
            // ###BEGIN###{Desktop}
            // ###BEGIN###{!DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (!Q('id_DeskVO').checked) { return desktop.m.handleKeyUp(e); } }
            // ###END###{!DesktopInband}
            // ###BEGIN###{DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (Q('id_DeskVO').checked) return; if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.handleKeyUp(e); desktop.m.sendKeepAlive(); } else { return desktop.m.handleKeyUp(e); } }
            // ###END###{DesktopInband}
            // ###END###{Desktop}
            // ###BEGIN###{Terminal}
            if (currentView == 13 && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
            // ###END###{Terminal}
        }

        function handleKeyDown(e) {
            //console.log('handleKeyDown', e);
            if (xxdialogMode) return;
            // ###BEGIN###{Desktop}
            // ###BEGIN###{!DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (!Q('id_DeskVO').checked) { return desktop.m.handleKeyDown(e); } }
            // ###END###{!DesktopInband}
            // ###BEGIN###{DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (Q('id_DeskVO').checked) return; if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.handleKeyDown(e); desktop.m.sendKeepAlive(); } else { return desktop.m.handleKeyDown(e); } }
            // ###END###{DesktopInband}
            // ###END###{Desktop}
            // ###BEGIN###{Terminal}
            if (currentView == 13 && terminal.State == 3) return terminal.m.TermHandleKeyDown(e);
            // ###END###{Terminal}
            // ###BEGIN###{ComputerSelector-Local}
            if (currentView == 101) {
                if (e.keyCode == 38) { var selectprev = null; for (var y in computerlist) { if (currentcomputer.h == computerlist[y].h) { if (selectprev != null) { computerSelect(null, selectprev); } } else { selectprev = computerlist[y].h; } } } // Up key
                if (e.keyCode == 40) { var selectnext = 0; for (var y in computerlist) { if (selectnext == 1) { selectnext = 2; computerSelect(null, computerlist[y].h); } else { if (currentcomputer.h == computerlist[y].h) { selectnext = 1; } } } } // Down key
            }
            // ###END###{ComputerSelector-Local}
        }

        function handleKeyPress(e) {
            //console.log('handleKeyPress', e);
            if (xxdialogMode) return;
            // ###BEGIN###{ComputerSelector-Local}
            if (currentView == 101) {
                if ((!filterFocus) && (e.keyCode != 0)) { Q('computerFilter').value = ((Q('computerFilter').value + String.fromCharCode(e.keyCode))); computerFilterFunc(); }
            }
            // ###END###{ComputerSelector-Local}
            // ###BEGIN###{Desktop}
            // ###BEGIN###{!DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (!Q('id_DeskVO').checked) { return desktop.m.handleKeys(e); } }
            // ###END###{!DesktopInband}
            // ###BEGIN###{DesktopInband}
            if (currentView == 14 && desktop.State == 3) { if (Q('id_DeskVO').checked) return; if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.handleKeys(e); desktop.m.sendKeepAlive(); } else { return desktop.m.handleKeys(e); } }
            // ###END###{DesktopInband}
            // ###END###{Desktop}
            // ###BEGIN###{Terminal}
            if (currentView == 13 && terminal.State == 3) return terminal.m.TermHandleKeys(e);
            // ###END###{Terminal}
            // ###BEGIN###{SessionRecording}
            if (currentView == 104) {
                if (e.keyCode == 32) { srec_togglePause(); haltEvent(e); }
                if (e.keyCode == 49) { Q('srec_PlaySpeed').value = 4; haltEvent(e); }
                if (e.keyCode == 50) { Q('srec_PlaySpeed').value = 2; haltEvent(e); }
                if (e.keyCode == 51) { Q('srec_PlaySpeed').value = 1; haltEvent(e); }
                if (e.keyCode == 52) { Q('srec_PlaySpeed').value = 0.5; haltEvent(e); }
                if (e.keyCode == 53) { Q('srec_PlaySpeed').value = 0.25; haltEvent(e); }
                if (e.keyCode == 54) { Q('srec_PlaySpeed').value = 0.1; haltEvent(e); }
                if (e.keyCode == 48) { srec_pause(); srec_restart(); haltEvent(e); }
            }
            // ###END###{SessionRecording}
        }

        var connectFunc = null;
        var connectFuncTag = null;
        function connect(host, port, user, pass, tls, func, functag) {
            go(0);
            fullscreenonly = false;
            connectFunc = func;
            connectFuncTag = functag;

            // ###BEGIN###{Desktop}
            if (urlvars['kvm'] == 1) { go(14); }
            if ((urlvars['kvmfull'] == 1) || (urlvars['kvmonly'] == 1)) { go(14); deskToggleFull(urlvars['kvmonly'] == 1); }
            // ###END###{Desktop}
            // ###BEGIN###{Terminal}
            if (urlvars['sol'] == 1) { go(13); }
            // ###END###{Terminal}

            // ###BEGIN###{Mode-NodeWebkit}
            var tlsoptions = {};
            // ###BEGIN###{CertificateManager}

            // Create a list of trusted certificates in PEM format
            var trustedCertStringsPem = [];
            for (var y in certificateStore) {
                var certificate = certificateStore[y];
                if (certificate['trusted'] == true) { trustedCertStringsPem.push('-----BEGIN CERTIFICATE-----\n' + certificate['certbin'] + '\n-----END CERTIFICATE-----\n'); }
            }
            tlsoptions.ca = trustedCertStringsPem;

            // Setup out console TLS authentication certificate
            var authcert = getTlsAuthCertificate();
            if (authcert != null) {
                tlsoptions.cert = forge.pki.certificateToPem(authcert['cert']);
                tlsoptions.key = forge.pki.privateKeyToPem(authcert['privateKey']);
            }

            // ###END###{CertificateManager}

            // ###BEGIN###{!MeshServerConnect}
            wsstack = WsmanStackCreateService(host, port, user, pass, tls, tlsoptions);
            // ###END###{!MeshServerConnect}
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                wsstack = WsmanStackCreateService(currentcomputer._id, null, null, null, 0, meshCentralServer);
            } else {
                wsstack = WsmanStackCreateService(host, port, user, pass, tls, tlsoptions);
            }
            // ###END###{MeshServerConnect}

            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            wsstack = WsmanStackCreateService(host, port, user, pass, tls);
            // ###END###{!Mode-NodeWebkit}
            amtstack = AmtStackCreateService(wsstack);
            amtstack.onProcessChanged = onProcessChanged;

            // Setup TLS checking
            // ###BEGIN###{Mode-NodeWebkit}
            wsstack.comm.xtlsSkipHostCheck = NW_SkipTlsHostnameCheck;
            if (NW_TlsSecurityMode == 0) { wsstack.comm.xtlsFingerprint = 0; }
            else { wsstack.comm.xtlsFingerprint = currentcomputer['tlscerthash'] ? currentcomputer['tlscerthash'] : currentcomputer['tlscerthash2']; }
            // ###END###{Mode-NodeWebkit}

            // Hide TLS indicator
            // ###BEGIN###{Mode-NodeWebkit}
            QV('tlsNotification1', false);
            QV('tlsNotification2', false);
            QV('tlsNotification3', false);
            QV('tlsNotification4', false);
            // ###END###{Mode-NodeWebkit}

            // Setup Digest Realm checking
            // ###BEGIN###{ComputerSelector}
            if (currentcomputer['digestrealm']) { wsstack.comm.digestRealmMatch = currentcomputer['digestrealm']; }
            // ###END###{ComputerSelector}

            // Hide most of the left menu options, we will see them as we load data
            for (var i = 2; i < 25; i++) { QV('go' + i, false); }
            QV('go8', true); // Network Settings
            // ###BEGIN###{Terminal}
            QV('go13', false); // Terminal
            // ###BEGIN###{!Mode-NodeWebkit}
            QE('TermWD', false);
            // ###END###{!Mode-NodeWebkit}
            // ###END###{Terminal}
            // ###BEGIN###{Desktop}
            //QV('go14', false); // Desktop
            // ###END###{Desktop}
            //QV('go15', false); // Audit Log
            // ###BEGIN###{WsmanBrowser}
            QV('go12', true); // WSMAN Browser
            // ###END###{WsmanBrowser}
            // ###BEGIN###{Certificates}
            //QV('go16', false); // Security Settings
            // ###END###{Certificates}
            // ###BEGIN###{RemoteAccess}
            //QV('go17', false); // Remote Access
            // ###END###{RemoteAccess}
            // ###BEGIN###{Scripting-Editor}
            QV('go20', true); // Scripting Editor
            // ###END###{Scripting-Editor}

            // ###BEGIN###{Storage}
            // ###BEGIN###{Mode-Firmware}
            //QH('storagelinks', '');
            // ###END###{Mode-Firmware}
            // ###END###{Storage}

            // Clear the displayed power state
            // ###BEGIN###{Terminal}
            QH('id_p13power', ''); // Terminal
            // ###END###{Terminal}
            // ###BEGIN###{Desktop}
            QH('id_p14power', ''); // Desktop
            // ###END###{Desktop}

            // Clear everything, make sure all connection state is reset.
            amtversion = amtversionmin = amtFirstPull = 0;
            amtsysstate = amtdeltatime = amtlogicalelements = HardwareInventory = undefined;
            amtPowerBootCapabilities = null;
            xxAccountFetch = 999;
            // ###BEGIN###{PowerControl}
            // ###BEGIN###{!Mode-MeshCentral2}

            if (!urlvars['norefresh']) { amtPowerPollTimer = setInterval(PullPowerState, 5000); }

            // ###END###{!Mode-MeshCentral2}
            // ###END###{PowerControl}

            // Show loading on all panels
            QH('id_TableSysStatus', LoadingHtml);
            // ###BEGIN###{NetworkSettings}
            QH('id_TableNetworkSettingsSpan', LoadingHtml);
            amtwirelessif = -1;
            // ###BEGIN###{Wireless}
            xxWireless = undefined;
            QH('id_TableWifi2', '');
            // ###END###{Wireless}
            // ###END###{NetworkSettings}
            // ###BEGIN###{HardwareInfo}
            QH('id_TableSysInfo', LoadingHtml);
            // ###END###{HardwareInfo}

            xxAccountAdminName = null;
            xxAccountRealmInfo = {};
            QH('id_TableUserAccounts', LoadingHtml);
            // ###BEGIN###{EventLog}
            eventmessages = null;
            QH('id_TableEventLog','');
            QH('id_TableEventLog2',LoadingHtml);
            // ###END###{EventLog}
            // ###BEGIN###{AuditLog}
            auditLog = null;
            QH('id_TableAuditLog1', '');
            QH('id_TableAuditLog2', LoadingHtml);
            // ###END###{AuditLog}
            // ###BEGIN###{Certificates}
            xxCertificates = null;
            QH('id_TableCerts', LoadingHtml);
            // ###END###{Certificates}
            // ###BEGIN###{WsmanBrowser}
            QH('id_wsresults', '');
            // ###END###{WsmanBrowser}
            // ###BEGIN###{IDER}
            iderStop();
            // ###END###{IDER}
            // ###BEGIN###{RemoteAccess}
            xxRemoteAccess = null;
            xxEnvironementDetection = null;
            xxCiraServers = null;
            xxUserInitiatedCira = null;
            xxRemoteAccessCredentiaLinks = null;
            xxMPSUserPass = null;
            xxPolicies = null;
            QH('id_TableRemoteAccess', LoadingHtml);
            // ###END###{RemoteAccess}
            // ###BEGIN###{AgentPresence}
            QH('id_TableSystemAgentPresence', LoadingHtml);
            // ###END###{AgentPresence}
            // ###BEGIN###{SystemDefense}
            xxSystemDefense = null;
            xxSystemDefenceLinkedPolicy = {};
            xxUpdatingDefenseStats = false;
            xxFilterStatistics = [{}, {}]; // Wired and wireless interface stats
            xxFilterStatisticsTimer = null;
            xxFilterStatisticsTimerActive = false;
            QH('id_TableSystemDefense', LoadingHtml);
            // ###END###{SystemDefense}
            // ###BEGIN###{Desktop}
            QE('id_DeskCAD', false);
            // ###BEGIN###{DesktopClipboard}
            QE('id_DeskKvmClipButton', false);
            // ###END###{DesktopClipboard}
            QE('DeskWD', false);
            QE('deskkeys', false);
            if (urlvars['kvmviewonly']) { QE('id_DeskVO', false); Q('id_DeskVO').checked = true; }
            // ###BEGIN###{DesktopType}
            QE('id_DeskType', false);
            // ###END###{DesktopType}
            // ###END###{Desktop}

            // ###BEGIN###{Desktop-Multi}
            desktopScreenInfo = null;
            // ###END###{Desktop-Multi}

            // Start pulling Intel AMT information
            amtstack.BatchEnum('', ['CIM_SoftwareIdentity', '*AMT_SetupAndConfigurationService'], processSystemVersion); // Get Intel AMT version information and plenty more
            //amtstack.Enum('CIM_LogicalElement', processSystemVersion); // Get Intel AMT version information and plenty more

            // ###BEGIN###{VersionWarning}
            QV('id_versionWarning', false);
            // ###END###{VersionWarning}

            // ###BEGIN###{Scripting-Editor}
            fupdatescript();
            // ###END###{Scripting-Editor}
        }

        function disconnect() {
            // ###BEGIN###{Desktop-Multi}
            if (desktopPollTimer != null) {clearInterval(desktopPollTimer); desktopPollTimer = null; }
            // ###END###{Desktop-Multi}

            // ###BEGIN###{Mode-NodeWebkit}
            if (urlvars['host']) {
                require('nw.gui').Window.get().close();
                //require('nw.gui').App.quit();
                return;
            }
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{Desktop}
            if (fullscreen) deskToggleFull();
            // ###END###{Desktop}

            // ###BEGIN###{IDER}
            iderStop();
            // ###END###{IDER}

            // ###BEGIN###{PowerControl}
            // ###BEGIN###{!Mode-MeshCentral2}
            if (amtPowerPollTimer != null) { clearInterval(amtPowerPollTimer); amtPowerPollTimer = null; }
            // ###END###{!Mode-MeshCentral2}
            // ###END###{PowerControl}

            // ###BEGIN###{SystemDefense}
            StopDefenseStatsTimer();
            // ###END###{SystemDefense}

            // ###BEGIN###{Scripting}
            script_Stop();
            // ###END###{Scripting}
            // ###BEGIN###{Scripting-Editor}
            breakScriptButton();
            // ###END###{Scripting-Editor}

            dialogclose(0);
            // ###BEGIN###{!Mode-MeshCentral2}
            QH('id_computername', '');
            // ###END###{!Mode-MeshCentral2}
            if (amtstack) {
                amtstack.onProcessChanged = null; // Un-hook progress indicator
                amtstack.CancelAllQueries(999); // Fail all pending WSMAN calls. Set to 999 to indicate not to call back any of the pending calls with errors.
                amtstack = null;
            }
            cleanup();
            wsstack = null;
            delete amtstack;
            onProcessChanged(0, 1);
            go(101);
            // ###BEGIN###{!Mode-MeshCentral2}

            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                QH('id_computername', format("Remote Management Console v{0}, Server: {1}", version, meshCentralServer.host));
            } else {
                QH('id_computername', format("Remote Management Console v{0}", version));
            }
            // ###END###{MeshServerConnect}
            // ###BEGIN###{!MeshServerConnect}
            QH('id_computername', format("Remote Management Console v{0}", version));
            // ###END###{!MeshServerConnect}
            
            // ###END###{!Mode-MeshCentral2}
            // ###BEGIN###{Mode-NodeWebkit}
            require('nw.gui').Window.get().title = NW_WindowTitle;
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{Mode-MeshCentral2}
            Q('xconnectbutton1').value = "Connect";
            QH('id_messageviewstr', "Disconnected");
            go(100);
            // ###END###{Mode-MeshCentral2}
        }

        function onProcessChanged(a, b) {
            QS('id_progressbar').width = ((a * 100) / b) + '%';
            if (a == 0) refreshButtons(true); // If nothing is being done, re-enable refresh buttons

            // ###BEGIN###{Mode-NodeWebkit}
            // Don't do any WSMAN if we don't need to do it.
            if ((urlvars['kvmonly'] == 1) || (fullscreenonly == true)) return;
            // ###END###{Mode-NodeWebkit}

            // If there is nothing being done now, see if we can pull more information
            if (a != 0 || !amtstack) return;
            if ((amtversion > 0) && ((amtFirstPull & 64) == 0)) {
                amtFirstPull |= 64;
                PullPowerPolicy();
                // ###BEGIN###{EventSubscriptions}
                subscriptionsFilters = null;
                PullEventSubscriptions();
                // ###END###{EventSubscriptions}
                // ###BEGIN###{AgentPresence}
                PullWatchdog();
                // ###END###{AgentPresence}

                // ###BEGIN###{Scripting-Editor}
                scriptViewButton(script_BuildingBlocks?1:0);
                // ###END###{Scripting-Editor}

                if (amtversion > 5) {
                    // ###BEGIN###{Certificates}
                    PullCertificates();
                    // ###END###{Certificates}
                    // ###BEGIN###{RemoteAccess}
                    PullRemoteAccess();
                    // ###END###{RemoteAccess}
                }
                return;
            }
            // ###BEGIN###{HardwareInfo}
            if ((amtFirstPull & 1) == 0) { PullHardware(); return; }
            // ###END###{HardwareInfo}
            // ###BEGIN###{EventLog}
            if ((amtFirstPull & 16) == 0) { PullEventLog(); return; }
            // ###END###{EventLog}
            // ###BEGIN###{AuditLog}
            if ((amtFirstPull & 32) == 0) { PullAuditLog(); return; }
            // ###END###{AuditLog}
        }

// ###BEGIN###{Mode-LMS}
        function toolmenuclick(x) {
            QV('id_menuitem1', currentView == 101);
            // ###BEGIN###{USBSetup}
            QV('id_menuitem2', currentView == 102);
            // ###END###{USBSetup}
            // ###BEGIN###{CertificateManager}
            QV('id_menuitem3', currentView == 103);
            // ###END###{CertificateManager}
            // ###BEGIN###{SessionRecording}
            QV('id_menuitem4', currentView == 104);
            // ###END###{SessionRecording}

            var d = (QS('id_computerSelectorMenu').display == 'none');
            if (d == true && xxdialogMode) return;
            xxdialogMode = (d == true)?999:undefined;
            QV('id_computerSelectorMenu', d);
            if (x == 0) return;
            go(x);
        }
// ###END###{Mode-LMS}

// ###BEGIN###{ComputerSelector}

        var computerlist = [];
        var currentcomputer = null;
        var computersRunningScripts = 0;

        function toolmenuclick(x) {
            QV('id_menuitem1', currentView == 101);
            // ###BEGIN###{USBSetup}
            QV('id_menuitem2', currentView == 102);
            // ###END###{USBSetup}
            // ###BEGIN###{CertificateManager}
            QV('id_menuitem3', currentView == 103);
            // ###END###{CertificateManager}
            // ###BEGIN###{SessionRecording}
            QV('id_menuitem4', currentView == 104);
            // ###END###{SessionRecording}

            var d = (QS('id_computerSelectorMenu').display == 'none');
            if (x == -1) { QV('id_computerSelectorMenu', false); xxdialogMode = undefined; return; }
            if (d == true && xxdialogMode) return;
            xxdialogMode = (d == true)?999:undefined;
            QV('id_computerSelectorMenu', d);
            if (x <= 0) return;
            go(x);
        }

        function computerFilterFunc() {
            var filter = computerFilter.value.toLowerCase();
            for (var w in computerlist) { QV('CX-' + computerlist[w].h, filter == '' || computerlist[w].checked == true || computerlist[w]['host'].toLowerCase().indexOf(filter) >= 0 || computerlist[w]['name'].toLowerCase().indexOf(filter) >= 0); }
        }

        // ###BEGIN###{ComputerSelector-Local}
        function addComputer() {
            if (xxdialogMode) return;

            // Build the list of groups
            var groups = [], x = '';
            for (var y in computerlist) { var computer = computerlist[y]; if ((computer.tags != null) && (computer.tags != '') && (groups.indexOf(computer.tags) == -1) && (computer.tags.indexOf('"') == -1)) { groups.push(computer.tags); } }
            groups.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
            for (var y in groups) { x += '<option value="' + groups[y] + '">'; }
            QH('d4devGroups', x);

            // Display the dialog box
            d4name.value = d4tags.value = d4hostname.value = d4password.value = '';
            d4username.value = "admin";
            if (kerberos != null) {
                QH('d4security', '<option value=0>' + "Digest / None" + '</option><option value=1>' + "Digest / TLS" + '</option><option value=2>' + "Kerberos / None" + '</option><option value=3>' + "Kerberos / TLS" + '</option>');
            } else {
                QH('d4security', '<option value=0>' + "Digest / None" + '</option><option value=1>' + "Digest / TLS" + '</option>');
            }
            d4security.value = 0;
            setDialogMode(4, "Add Computer", 3, function () { addComputerButton(); });
            updateComputerDialog();
            d4name.focus();
        }

        // Toggle the select of all computers
        // TODO: Fix problem with this combined with filter box
        function selectAllComputers() {
            var x = false;
            for (var y in computerlist) { if (computerlist[y].checked == false) { x = true; } }
            for (var y in computerlist) { computerlist[y].checked = x; Q('SJ-' + computerlist[y]['h']).checked = x; } // TODO: Only select or un-select when element is visible
        }

        function deleteComputers() {
            if (xxdialogMode) return;
            // Figure out how many computers are selected.
            var clist = [];
            for (var y in computerlist) { if (computerlist[y].checked == true) { clist.push(computerlist[y]); } }
            if (clist.length == 0) { clist.push(currentcomputer); }
            if (clist.length == 1) {
                setDialogMode(11, "Delete Computers", 3, deleteComputersEx, '<br>' + "Delete computer?", clist);
            } else {
                setDialogMode(11, "Delete Computers", 3, deleteComputersEx, '<br>' + format("Delete {0} computers?", clist.length), clist);
            }
        }

        function deleteComputersEx(button, clist) {
            for (var i in clist) {
                var handleToDelete = clist[i]['h'];
                if ((currentcomputer != null) && (currentcomputer['h'] == handleToDelete)) { currentcomputer = null; }
                for (x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == handleToDelete) { computerlist.splice(x, 1); } }
            }
            saveComputers();
            updateComputerList();
            updateComputerDetails();
        }

        function newComputerList() {
            if (xxdialogMode) return;
            QH('id_dialogMessage', "Clear list of known Intel&reg; AMT computers?");
            setDialogMode(1, "New Computer List", 3, newComputerListOk);
        }

        function newComputerListOk(r) {
            computerlist = [];
            currentcomputer = null;
            // ###BEGIN###{!Mode-NodeWebkit}
            idx_d18computerfilename.value = 'computerlist.json';
            // ###END###{!Mode-NodeWebkit}
            saveComputers();
            updateComputerList();
        }
        
        function openComputerList() {
            if (xxdialogMode) return;
            // ###BEGIN###{!Mode-NodeWebkit}
            setDialogMode(17, "Open Computer List", 3, openComputerListOk);
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = Q('idx_d17computerlistfile');
            if (chooser.getAttribute('eventset') != 1) {
                chooser.setAttribute('eventset', '1');
                chooser.addEventListener('change', NW_LoadComputersEx, false);
            }
            chooser.value = null;
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }

        function openComputerListOk(r) {
            if (r != 1) return;
            var x = Q('idx_d17computerlistfile');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = function(file) { onComputerListRead(file, Q('idx_d17computerlistfile').files[0].name); }
            reader.readAsBinaryString(x.files[0]);
        }
        
        function onComputerListRead(file, name, pass) {
            var x;
            if (name.toLowerCase().endsWith('.csv')) {
                // Load from a CSV file
                x = { computers: [] };
                var lines = file.target.result.split('\r\n').join('\n').split('\n'), headers = {}, count = 0;
                for (var i in lines) {
                    var values = lines[i].split(',');
                    if (i == 0) {
                        // Fill the headers
                        for (var j in values) {
                            if (values[j] == 'Intel AMT FQDN') { headers[j] = 'name'; }
                            if (values[j] == 'Intel AMT IPv4') { headers[j] = 'host'; }
                            if (values[j] == 'Intel AMT Version') { headers[j] = 'ver'; }
                            //if (values[j] == 'Last Connection Time') { headers[j] = 'date'; }
                        }
                    } else {
                        // Fill data
                        var computerEntry = {};
                        for (var j in values) {
                            if (headers[j] && (values[j].length > 0)) { computerEntry[headers[j]] = values[j]; }
                        }
                        if (computerEntry.host || computerEntry.name) {
                            if (computerEntry.host == null) { computerEntry.host = computerEntry.name; }
                            if (computerEntry.user == null) { computerEntry.user = 'admin'; }
                            if (computerEntry.pass == null) { computerEntry.pass = ''; }
                            if (computerEntry.tls == null) { computerEntry.tls = 1; }
                            x.computers.push(computerEntry);
                            count++;
                        }
                    }
                }
                if (count == 0) { x = {}; }
            } else {
                try { x = JSON.parse(file.target.result); } catch (ex) { }
                // ###BEGIN###{Mode-NodeWebkit}
                if (x && x['magic'] == '3209ruwpcoinaT4r9w347t0e4ug') {
                    if (pass) {
                        // Decrypt the file
                        x = getDecryptedData(x, pass);
                        if (x && (x != null)) { x = JSON.parse(x); }
                    } else {
                        // Prompt to the password
                        var x = "The selected file requires a password." + '<br/><br/><div style=height:26px><input id=idx_filepass type=password style=float:right;width:200px onkeyup=filePasswordDialogUpdate()><div>' + "Password" + '</div></div>';
                        setDialogMode(11, "File Password", 3, onComputerListReadEx, x, [file, name]);
                        filePasswordDialogUpdate();
                        return;
                    }
                }
                // ###END###{Mode-NodeWebkit}
            }
            if (!x || !x['computers']) {
                messagebox("Open File", "Invalid or corrupt computer list file. Unable to open.");
            } else {
                // ###BEGIN###{!Mode-NodeWebkit}
                idx_d18computerfilename.value = name;
                // ###END###{!Mode-NodeWebkit}
                currentcomputer = null;
                computerlist = x['computers'];
                for (var i in computerlist) { computerlist[i]['h'] = Math.random(); computerlist[i].checked = false; }
                updateComputerList();
                saveComputers();
            }
        }

        function onComputerListReadEx(button, tag) { onComputerListRead(tag[0], tag[1], Q('idx_filepass').value); }
        function filePasswordDialogUpdate() { QE('idx_dlgOkButton', passwordcheck(Q('idx_filepass').value)); }

        // ###BEGIN###{FileSaver}

        function saveComputerListUpdate() {
            var ok = true;
            // ###BEGIN###{Mode-NodeWebkit}
            QV('d18showpassword', d18usepassword.checked);
            if (d18usepassword.checked == true) { ok = (passwordcheck(d18password1.value) && (d18password1.value == d18password2.value)) };
            // ###END###{Mode-NodeWebkit}
            QE('idx_dlgOkButton', ok);
        }

        function saveComputerList() {
            if (xxdialogMode) return;
            // ###BEGIN###{Mode-NodeWebkit}
            d18usepassword.checked = false;
            d18password1.value = '';
            d18password2.value = '';
            // ###END###{Mode-NodeWebkit}
            setDialogMode(18, "Save Computer List", 3, saveComputerListOk);
            saveComputerListUpdate();
        }

        function saveComputerListOk() {
            var computerlist2 = Clone(computerlist);
            for (var i in computerlist2) { delete computerlist2[i]['h']; delete computerlist2[i].checked; delete computerlist2[i]['consolemsg']; }
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(JSON.stringify({ 'webappversion':version, 'computers':computerlist2 }, null, '  ').replace(/\n/g, '\r\n')), idx_d18computerfilename.value);
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('nwsaveas', 'computerlist.json');
            chooser.addEventListener('change', function() {
                if (this.value == '') return;
                if (d18usepassword.checked == false) { 
                    require('fs').writeFile(this.value, JSON.stringify({ 'webappversion': version, 'computers': computerlist2 }, null, '  ').replace(/\n/g, '\r\n'), function () { });
                } else {
                    require('fs').writeFile(this.value, JSON.stringify(getEncryptedData(JSON.stringify({ 'webappversion': version, 'computers': computerlist2 }, null, '  '), d18password1.value), null, '  ').replace(/\n/g, '\r\n'), function () { });
                }
                this.value = '';
            }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }

        function getEncryptedData(dataStr, password) {
            var crypto = require('crypto');
            var salt = crypto.randomBytes(16);
            var key = crypto.pbkdf2Sync(password, salt, 128000, 16, 'sha512');
            var iv = Math.round((Math.pow(36, 13) - Math.random() * Math.pow(36, 12))).toString(36).slice(1);
            var cipher = crypto.createCipheriv('aes-256-gcm', key.toString('hex'), iv);
            var encrypted = cipher.update(dataStr, 'utf8', 'hex') + cipher.final('hex');
            return { 'magic': '3209ruwpcoinaT4r9w347t0e4ug', 'version': 1, 'salt': salt.toString('hex'), 'iv': iv, 'tag': cipher.getAuthTag().toString('hex'), 'data': encrypted };
        }

        function getDecryptedData(encryptedData, password) {
            var crypto = require('crypto');
            var salt = new require('buffer').Buffer(encryptedData['salt'], 'hex');
            var iv = encryptedData['iv'];
            var tag = new require('buffer').Buffer(encryptedData['tag'], 'hex');
            var data = encryptedData['data'];
            var key = crypto.pbkdf2Sync(password, salt, 128000, 16, 'sha512');
            var decipher = crypto.createDecipheriv('aes-256-gcm', key.toString('hex'), iv);
            decipher.setAuthTag(tag);
            var decrypted = decipher.update(data, 'hex', 'utf8') + decipher.final('utf8');
            return decrypted;
        }

        // ###END###{FileSaver}

        function updateComputerDialog() {
            var k = Q('d4security').value >= 2;
            QV('d4digest', !k);
            QV('d4kerb', k);
            var hostSplit = d4hostname.value.split(':');
            var hostnameok = (d4hostname.value.length > 0) && (hostSplit.length < 3);
            if (hostnameok && (hostSplit.length == 2)) { var hostport = parseInt(hostSplit[1]); hostnameok = (hostport > 0) && (hostport < 65536) && (hostport == hostSplit[1]); }
            QS('d4hostname')['background-color'] = (hostnameok ? 'white' : 'LightYellow');
            if (k && hostnameok) {
                QE('idx_dlgOkButton', d4hostname.value.length > 0);
            } else {
                QS('d4username')['background-color'] = (((d4username.value.length > 0) && (d4username.value != '*')) ? 'white' : 'LightYellow');
                QS('d4password')['background-color'] = (((d4username.value == '$$OsAdmin') || passwordcheck(d4password.value) || d4password.value == '') ? 'white' : 'LightYellow');
                QE('idx_dlgOkButton', d4hostname.value.length > 0 && d4username.value.length > 0 && d4username.value != '*' && ((d4username.value == '$$OsAdmin') || passwordcheck(d4password.value) || d4password.value == ''));
            }
        }

        function addComputerButton() {
            var k = Q('d4security').value >= 2;
            // ###BEGIN###{!Mode-NodeWebkit}
            if (k) {
                computerlist.push({ 'h': Math.random(), 'name': encodeURIComponent(d4name.value), 'host': encodeURIComponent(d4hostname.value), 'tags': encodeURIComponent(d4tags.value), 'user': '*', 'pass': encodeURIComponent(Q('d4kerberos').value), 'tls': d4security.value % 2 });
            } else {
                computerlist.push({ 'h': Math.random(), 'name': encodeURIComponent(d4name.value), 'host': encodeURIComponent(d4hostname.value), 'tags': encodeURIComponent(d4tags.value), 'user': encodeURIComponent(d4username.value), 'pass': encodeURIComponent(d4password.value), 'tls': d4security.value % 2 });
            }
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            if (k) {
                computerlist.push({ 'h': Math.random(), 'name': encodeURIComponent(d4name.value), 'host': encodeURIComponent(d4hostname.value), 'tags': encodeURIComponent(d4tags.value), 'user': '*', 'pass': encodeURIComponent(Q('d4kerberos').value), 'tls': d4security.value % 2, 'tlscerthash': getCertPinning(d4hostname.value) });
            } else {
                computerlist.push({ 'h': Math.random(), 'name': encodeURIComponent(d4name.value), 'host': encodeURIComponent(d4hostname.value), 'tags': encodeURIComponent(d4tags.value), 'user': encodeURIComponent(d4username.value), 'pass': encodeURIComponent(d4password.value), 'tls': d4security.value % 2, 'tlscerthash': getCertPinning(d4hostname.value) });
            }
            // ###END###{Mode-NodeWebkit}
            saveComputers();
            updateComputerList();
        }

        function computerSelector_FileSelectHandler(e) {
            haltEvent(e);
            if (e.dataTransfer == null || e.dataTransfer.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = function(file) { onComputerListRead(file, e.dataTransfer.files[0].name); }
            reader.readAsText(e.dataTransfer.files[0]);
        }

        function computerEdit(h) {
            if (xxdialogMode) return;
            var c = null;
            for (x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { c = computerlist[x]; } }

            // Build the list of groups
            var groups = [], x = '';
            for (var y in computerlist) { var computer = computerlist[y]; if ((computer.tags != null) && (computer.tags != '') && (groups.indexOf(computer.tags) == -1) && (computer.tags.indexOf('"') == -1)) { groups.push(computer.tags); } }
            groups.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
            for (var y in groups) { x += '<option value="' + groups[y] + '">'; }
            QH('d4devGroups', x);

            // If connected to a MeshCentral server, only edit the device name
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                var x = '<div style=height:26px><input id=d11deviceName style=float:right;width:200px value="' + decodeURIComponent(c['name'] ? c['name'] : '') + '"><div>' + "Friendly Name" + '</div></div>';
                setDialogMode(11, "Edit Device", 3, computerEditMeshOk, x, c);
                return;
            }
            // ###END###{MeshServerConnect}

            if (kerberos != null || c['user'] == '*') {
                QH('d4security', '<option value=0>' + "Digest / None" + '</option><option value=1>' + "Digest / TLS" + '</option><option value=2>' + "Kerberos / None" + '</option><option value=3>' + "Kerberos / TLS" + '</option>');
            } else {
                QH('d4security', '<option value=0>' + "Digest / None" + '</option><option value=1>' + "Digest / TLS" + '</option>');
            }
            d4name.value = decodeURIComponent(c['name']?c['name']:'');
            d4tags.value = decodeURIComponent(c['tags']?c['tags']:'');
            d4hostname.value = decodeURIComponent(c['host']);
            d4security.value = c['tls'] + ((c['user'] == '*')?2:0);
            if (c['user'] == '*') {
                d4kerberos.value = decodeURIComponent(c['pass']?c['pass']:'');
            } else {
                d4username.value = decodeURIComponent(c['user']?c['user']:'');
                d4password.value = decodeURIComponent(c['pass']?c['pass']:'');
            }
            setDialogMode(4, "Edit Device", 7, function (r) { computerEditOk(r, h); });
            updateComputerDialog();
            Q('d4name').focus();
        }

        // ###BEGIN###{MeshServerConnect}
        function computerEditMeshOk(button, c) {
            if (Q('d11deviceName').value != c.name) { meshCentralServer.send({ action: 'changedevice', nodeid: c._id, name: Q('d11deviceName').value }); }
        }
        // ###END###{MeshServerConnect}

        function computerEditOk(r, h) {
            if (r == 2) { computerRemoveEx(h); return; }
            var c = null;
            for (x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { c = computerlist[x]; } }
            c['name'] = decodeURIComponent(d4name.value);
            c['tags'] = decodeURIComponent(d4tags.value);
            c['host'] = decodeURIComponent(d4hostname.value);
            if (d4security.value < 2) {
                // Digest authentication
                c['user'] = decodeURIComponent(d4username.value);
                c['pass'] = decodeURIComponent(d4password.value);
            } else {
                // Kerberos authentication
                c['user'] = '*';
                c['pass'] = decodeURIComponent(d4kerberos.value);
            }
            c['tls'] = d4security.value % 2;

            //for (x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { computerlist.splice(x, 1); } }
            //var c = { 'h': h, "name": d4name.value, "host": d4hostname.value, "user": d4username.value, "pass": d4password.value, "tls": d4security.value };
            //computerlist.push(c);
            //if (currentcomputer['h'] == c['h']) { currentcomputer = c; }
            saveComputers();
            //computerSelect();
            updateComputerList();
            updateComputerDetails();
        }

        function computerRemoveEx(h) {
            if (currentcomputer['h'] == h) currentcomputer = null;
            for (x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { computerlist.splice(x, 1); } }
            saveComputers();
            updateComputerList();
            updateComputerDetails();
        }

        function onFilterFocus(x) { filterFocus = x; }

        // ###END###{ComputerSelector-Local}

        function updateComputerList() {
            QH('id_computerList', '');
            // ###BEGIN###{MeshServerConnect}
            if ((meshCentralServer != null) && (computerlist.length == 0)) {
                QV('id_noKnownComputers', false);
                if (meshCentralServer.socketState < 3) {
                    QH('id_computerList', '<div style=width:99%;text-align:center;margin-top:36px;color:gray>' + "Connecting..." + '</div>');
                } else {
                    QH('id_computerList', '<div style=width:99%;text-align:center;margin-top:36px;color:gray>' + "No Intel&reg; AMT computers found on this account." + '</div>');
                }
                QV('id_noKnownComputers', false);
            } else {
                QV('id_noKnownComputers', computerlist.length == 0);
            }
            // ###END###{MeshServerConnect}
            // ###BEGIN###{!MeshServerConnect}
            QV('id_noKnownComputers', computerlist.length == 0);
            // ###END###{!MeshServerConnect}
            QV('computerFilter', computerlist.length != 0);
            // ###BEGIN###{FileSaver}
            QE('saveComputersButton', computerlist.length != 0);
            // ###END###{FileSaver}
            // ###BEGIN###{Scripting}
            computersRunningScripts = 0;
            var computersWithScriptsMsgs = 0;
            
            for (var y in computerlist) { if (computerlist[y].scriptstate) computersRunningScripts++; if (computerlist[y]['consolemsgs']) computersWithScriptsMsgs++; }
            // ###BEGIN###{Mode-NodeWebkit}
            if (urlvars['autoexit'] && computersRunningScripts == 0 && computersWithScriptsMsgs > 0) {
                require('nw.gui').Window.get().close();
                //require('nw.gui').App.quit();
                return;
            } // Exit if no scripts are running
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{ComputerSelectorToolbar}
            QE('idx_runScriptOnComputersButton', computerlist.length != 0);
            // ###BEGIN###{MeshServerConnect}
            QV('id_noScriptButtons', (computersRunningScripts == 0) && (meshCentralServer == null));
            QV('idx_disconnectMeshCentralButton', meshCentralServer != null);
            QV('idx_runScriptOnComputersButton', meshCentralServer == null);
            QV('toolmenuicondiv', meshCentralServer == null);
            // ###BEGIN###{Mode-NodeWebkit}
            QV('LeftMenuMyCerts', meshCentralServer == null);
            QV('LeftMenuMyUsb', meshCentralServer == null);
            QV('LeftMenuPlayer', meshCentralServer == null);
            // ###END###{Mode-NodeWebkit}
            // ###END###{MeshServerConnect}
            // ###BEGIN###{!MeshServerConnect}
            QV('id_noScriptButtons', computersRunningScripts == 0);
            // ###END###{!MeshServerConnect}
            idx_runScriptOnComputersButton.value = (computersRunningScripts > 0 ? "Stop All Scripts" : "Run Script...")
            // ###END###{ComputerSelectorToolbar}
            // ###END###{Scripting}
            QV('id_computerDetailsParent', computerlist.length != 0);
            QS('id_computerListParent').right = (computerlist.length == 0 ? 0 : '300px');
            computerlist.sort(function (a, b) { var aa = a['name'] ? a['name'].toLowerCase() : a['host'].toLowerCase(); var bb = b['name'] ? b['name'].toLowerCase() : b['host'].toLowerCase(); if (aa > bb) { return 1; } if (aa < bb) { return -1; } return 0; });
            if (currentcomputer == null && computerlist.length > 0) { currentcomputer = computerlist[0]; }

            // Built a sorted list of groups
            var groups = [''], groupHtml = {};
            for (var y in computerlist) { var computer = computerlist[y]; if ((computer.tags != null) && (groups.indexOf(computer.tags) == -1)) { groups.push(computer.tags); } }
            groups.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
            for (var y in groups) { groupHtml[groups[y]] = ''; }

            // Go thru each computer and create the HTML entry
            for (var y in computerlist) {
                var computer = computerlist[y], extra = [], group = '', disabled = false;
                if (computer.tags != null) { group = computer.tags; }
                if (computer['user'] == '*') { extra.push("Kerberos"); } else { if (computer['user']) { extra.push(EscapeHtml(decodeURIComponent(computer['user']))); } }
                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer != null) {
                    var securityok = false;
                    if (computer['conn']) {
                        if ((computer['conn'] & 2) != 0) { extra.push("CIRA"); securityok = true; } else {
                            if ((computer['conn'] & 4) != 0) { extra.push("Direct"); }
                            else if ((computer['conn'] & 8) != 0) { extra.push("Relay"); }
                        }
                    }
                    if (securityok == true) {
                        if (computer['tls'] != 0) { extra.push("TLS"); }
                    } else {
                        extra.push((computer['tls'] == 0) ? NoBreak("No Security") : "TLS");
                    }
                } else {
                    extra.push((computer['tls'] == 0) ? NoBreak("No Security") : "TLS");
                }
                // ###END###{MeshServerConnect}
                // ###BEGIN###{!MeshServerConnect}
                extra.push((computer['tls'] == 0) ? NoBreak("No Security") : "TLS");
                // ###END###{!MeshServerConnect}
                var name = decodeURIComponent(computer['host']);
                if (computer['name'] && computer['name'] != '') name = decodeURIComponent(computer['name']);

                var x = '<div id=CX-' + computer['h'] + ' ondblclick=computerEdit(' + computer['h'] + ')>';
                // ###BEGIN###{Look-Commander}
                // ###BEGIN###{ComputerSelectorScanner}
                var gray = false;
                if (NW_AmtScanMenuItem && (NW_AmtScanMenuItem.checked == true)) { gray = ((!globalAmtScanner.scanTable[computer['h']]) || (globalAmtScanner.scanTable[computer['h']].scanstate != 1)); }
                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer != null) { disabled = gray = ((computer.conn & 14) == 0); }
                // ###END###{MeshServerConnect}
                // ###BEGIN###{!ComputerSelectorNoImages}
                x += '<div id=SI-' + computer['h'] + ' class=\"j' + (computer['icon'] ? computer['icon'] : 1) + (gray ? ' gray' : '') + '\" style=float:left;margin-left:4px;margin-right:4px></div>';
                // ###END###{!ComputerSelectorNoImages}
                // ###END###{ComputerSelectorScanner}
                // ###BEGIN###{!ComputerSelectorScanner}
                // ###BEGIN###{!ComputerSelectorNoImages}
                x += '<div id=SI-' + computer['h'] + ' class=\"j' + (computer['icon'] ? computer['icon'] : 1) + '\" style=float:left;margin-left:4px;margin-right:4px></div>';
                // ###END###{!ComputerSelectorNoImages}
                // ###END###{!ComputerSelectorScanner}
                // ###END###{Look-Commander}

                // ###BEGIN###{ComputerSelectorNoImages}
                x += '<div><table style="height:24px;width:calc(100%);margin:3px;cursor:pointer;border:none" cellspacing=0 cellpadding=0';
                // ###END###{ComputerSelectorNoImages}
                // ###BEGIN###{!ComputerSelectorNoImages}
                x += '<div><table style="height:24px;width:calc(100% - 38px);margin:3px;cursor:pointer;border:none" cellspacing=0 cellpadding=0';
                // ###END###{!ComputerSelectorNoImages}

                // ###BEGIN###{ComputerSelector-Local}
                // ###BEGIN###{ContextMenus}
                var cmenus = [];
                // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                if ((computer.scriptstate == undefined) && (disabled == false)) {
                    cmenus.push("Connect" + '#computerConnect(event,' + computer['h'] + ')');
                    cmenus.push("Windowed Connect" + '#computerConnect(event,' + computer['h'] + ',100)');
                    cmenus.push('-');
                    cmenus.push("Desktop" + '#computerConnect(event,' + computer['h'] + ',1)');
                    cmenus.push("Desktop Only" + '#computerConnect(event,' + computer['h'] + ',3)');
                    cmenus.push("Terminal" + '#computerConnect(event,' + computer['h'] + ',4)');
                }
                // ###END###{!ComputerSelector-Local-ScriptOnly}
                // ###BEGIN###{Scripting}
                if (computer.scriptstate != null) cmenus.push("Stop Script" + '#computerStopScript(event,' + computer['h'] + ')');
                if (computer['consolemsgs'] != null) cmenus.push("Script Output..." + '#mscript_showComputerScriptOutput(' + computer['h'] + ')');
                // ###END###{Scripting}
                if (computer.scriptstate == null) cmenus.push("Edit..." + '#computerEdit(' + computer['h'] + ')');
                x += ' cm=\'' + cmenus.join('|') + '\'';
                // ###END###{ContextMenus}
                // ###END###{ComputerSelector-Local}
                x += ' onclick="computerSelect(event, ' + computer['h'] + ')" id=CI-' + computer['h'] + '>';
                x += '<td id=LCX-' + computer['h'] + ' class=g1 style=float:none>&nbsp;</td>' // Left side gray scale

                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer == null) {
                // ###END###{MeshServerConnect}
                // ###BEGIN###{ComputerSelectorScanner}
                if (NW_AmtScanMenuItem && (NW_AmtScanMenuItem.checked == true)) {
                    var scanstate = globalAmtScanner.scanTable[computer['h']], scancolor = '';
                    if (scanstate) { if (scanstate.scanstate == 1) scancolor = ';background-color:green'; if (scanstate.scanstate == 0) scancolor = ';background-color:red'; }
                    x += '<td style=width:12px title="' + "Intel&reg; AMT RMCP response" + '"><div id=SS-' + computer['h'] + ' class=computeritemcir style=' + scancolor + '></div>';
                }
                // ###END###{ComputerSelectorScanner}
                // ###BEGIN###{MeshServerConnect}
                }
                // ###END###{MeshServerConnect}

                // ###BEGIN###{Look-ISDU}
                x += '<td style=width:24px><img src=images-isdu/ComputerIcon.png style=padding-top:2px /></td>';
                // ###END###{Look-ISDU}
                // ###BEGIN###{Look-Commander}
                //x += '<td class=j' + (computer['icon'] ? computer['icon'] : 1) + '></td>';
                // ###END###{Look-Commander}
                // ###BEGIN###{Look-BrandedCommander}
                x += '<td><img src=images-BrandedCommander/ComputerIcon.png style=vertical-align:text-top /></td>';
                // ###END###{Look-BrandedCommander}
                // ###BEGIN###{Scripting}
                x += '<td style=width:10px><input id=SJ-' + computer['h'] + ' type=checkbox onclick=onComputerChecked()' + (computer.checked?' checked':'') + (computersRunningScripts>0?' disabled':'') + ' /></td>';
                // ###END###{Scripting}

                x += '<td align=left><b style=font-size:16px>' + EscapeHtml(name) + '</b></td>';

                // ###BEGIN###{!Scripting}
                // ###BEGIN###{ComputerSelector-Local-ScriptOnly}
                x += '<td align=right style=padding-right:5px>' + extra.join(', ') + '</td>';
                // ###END###{ComputerSelector-Local-ScriptOnly}
                // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                x += '<td align=right style=padding-right:5px>' + extra.join(', ') + '</td><td style=width:1px;padding-right:5px>' + AddButton2("Connect", 'computerConnect(event,' + computer['h'] + ')', disabled ? 'disabled=disabled' : '') + '</td>';
                // ###END###{!ComputerSelector-Local-ScriptOnly}
                // ###END###{!Scripting}
                // ###BEGIN###{Scripting}
                if (computersRunningScripts == 0) {
                    // ###BEGIN###{ComputerSelector-Local-ScriptOnly}
                    x += '<td align=right style=padding-right:5px>' + extra.join(', ') + '</td>';
                    // ###END###{ComputerSelector-Local-ScriptOnly}
                    // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                    x += '<td align=right style=padding-right:5px>' + extra.join(', ') + '</td><td style=width:1px;padding-right:5px>' + AddButton2("Connect", 'computerConnect(event,' + computer['h'] + ')', disabled?'disabled=disabled':'') + '</td>';
                    // ###END###{!ComputerSelector-Local-ScriptOnly}
                } else {
                    if (computer.scriptstate) { x += '<td align=right style=padding-right:5px id=XI-' + computer['h'] + '>' + EscapeHtml(computer['consolemsg']) + '</td><td style=width:1px>' + AddButton2("Stop", 'computerStopScript(event,' + computer['h'] + ')') + '</td>'; }
                }
                // ###END###{Scripting}

                x += '<td id=RCX-' + computer['h'] + ' class=g2 style=float:none>&nbsp;</td>' // Right side gray scale
                x += '</table></div></div>';

                groupHtml[group] += x; // Add this device to the proper group
            }

            // Append all the groups into the final HTML
            if (computerlist.length > 0) {
                var x = '';
                for (var y in groups) {
                    if (groups[y] != '') { x += '<div style="font-size:14px;border-bottom:1px solid lightgray;margin-left:4px;margin-top:6px"><b>' + EscapeHtml(groups[y]) + '</b></div>'; }
                    x += groupHtml[groups[y]];
                }
                QH('id_computerList', '<div style=width:99%>' + x + '</div>');
            }
            updateComputerDetails();
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(currentView);
            // ###END###{Mode-NodeWebkit}
        }

        function onComputerChecked() {
            for (var y in computerlist) { computerlist[y].checked = Q('SJ-' + computerlist[y]['h']).checked; }
        }

        function addComputerDetailsEntry(x, y) {
            //return '<div class=log style=border-radius:4px;padding:3px;margin-bottom:3px><div style=width:100%;font-size:9px>' + x + '</div><div style=width:100%>&nbsp;' + y + '</div></div>';
            return '<div style=border-radius:4px;padding:3px;margin-bottom:3px;background-color:#ddd><div style=width:100%;font-size:9px>' + x + '</div><div style=width:100%>&nbsp;' + y + '</div></div>';
        }

        function updateComputerDetails() {
            var x = '<div style=position:absolute;top:0;right:0;left:0;bottom:0>', disabled = false;
            if (currentcomputer != null) {
                // ###BEGIN###{Look-Commander}
                // Put the big computer logo
                // ###BEGIN###{!ComputerSelectorNoImages}
                x += '<div style=position:absolute;top:4px;left:4px;right:4px;bottom:80px>';
                if (currentcomputer['name']) x += '<div style=width:100%;text-align:center><b>' + EscapeHtml(decodeURIComponent(currentcomputer['name'])) + '</b></div>';
                // ###BEGIN###{ComputerSelectorScanner}
                var icon = 1, gray = false;
                if ((NW_AmtScanMenuItem) && (NW_AmtScanMenuItem.checked == true)) { gray = (!globalAmtScanner.scanTable[currentcomputer['h']]) || (globalAmtScanner.scanTable[currentcomputer['h']].scanstate != 1); }
                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer != null) { disabled = gray = ((currentcomputer.conn & 14) == 0); }
                // ###END###{MeshServerConnect}
                if (currentcomputer['icon']) { icon = parseInt(currentcomputer['icon']); }
                x += '<img ' + (gray ? 'class=gray ' : '') + 'src="images-commander/icons200-' + icon + '-1.png" onclick=showIconSelector() height=200 width=200 style=margin-left:50px;cursor:pointer></img>';
                // ###END###{ComputerSelectorScanner}
                // ###BEGIN###{!ComputerSelectorScanner}
                var icon = 1;
                if (currentcomputer['icon']) { icon = parseInt(currentcomputer['icon']); }
                x += '<img src="images-commander/icons200-' + icon + '-1.png" onclick=showIconSelector() height=200 width=200 style=margin-left:50px;cursor:pointer></img>';
                // ###END###{!ComputerSelectorScanner}
                // ###END###{!ComputerSelectorNoImages}

                x += '</div>';
                // ###END###{Look-Commander}

                var bottomButtons = '';
                var bottomButtonsHeight = 0;
                if (computersRunningScripts == 0) {
                    //bottomButtons += '<div style=position:fixed;bottom:8px;right:5px>';
                    bottomButtonsHeight = 14 + 20;
                    bottomButtons += '<div style=position:absolute;bottom:8px;left:4px;right:4px>';
                    // ###BEGIN###{Scripting}
                    if (currentcomputer['consolemsgs']) { bottomButtonsHeight += 20; bottomButtons += '<input type=Button value="' + "Show Script Output..." + '" style=width:292px onclick=mscript_showComputerScriptOutput(' + currentcomputer['h'] + ')><br>'; }
                    // ###END###{Scripting}
                    // ###BEGIN###{ComputerSelector-Local}
                    // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                    bottomButtons += '<input type=Button value="' + "Edit..." + '" style=width:146px onclick=computerEdit(' + currentcomputer['h'] + ')>';
                    bottomButtons += '<input type=Button value="' + "Connect" + '" style=width:146px onclick=computerConnect(event,' + currentcomputer['h'] + ') ' + (disabled ? 'disabled=disabled' : '') + '>';
                    // ###END###{!ComputerSelector-Local-ScriptOnly}
                    // ###BEGIN###{ComputerSelector-Local-ScriptOnly}
                    bottomButtons += '<input type=Button value="' + "Edit..." + '" style=width:292px onclick=computerEdit(' + currentcomputer['h'] + ')>';
                    // ###END###{ComputerSelector-Local-ScriptOnly}
                    // ###END###{ComputerSelector-Local}
                    // ###BEGIN###{!ComputerSelector-Local}
                    // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                    bottomButtons += '<input type=Button value="' + "Connect" + '" style=width:292px onclick=computerConnect(event,' + currentcomputer['h'] + ' ' + (disabled ? 'disabled=disabled' : '') + ')>';
                    // ###END###{!ComputerSelector-Local-ScriptOnly}
                    // ###END###{!ComputerSelector-Local}
                    bottomButtons += '</div>';
                } else {
                    // ###BEGIN###{Scripting}
                    if (currentcomputer.scriptstate || currentcomputer['consolemsgs']) {
                        //bottomButtons += '<div style=position:fixed;bottom:8px;right:5px>';
                        bottomButtonsHeight = 14;
                        bottomButtons += '<div style=position:absolute;bottom:8px;left:4px;right:4px>';
                        if (currentcomputer['consolemsgs'] != null) { bottomButtonsHeight += 20; bottomButtons += '<input type=Button value="' + "Show Script Output..." + '" style=width:292px onclick=mscript_showComputerScriptOutput(' + currentcomputer['h'] + ')><br>'; }
                        if (currentcomputer.scriptstate != null) { bottomButtonsHeight += 20; bottomButtons += '<input type=Button value="' + "Stop Script" + '" style=width:292px onclick=computerStopScript(event,' + currentcomputer['h'] + ')>'; }
                        bottomButtons += '</div>';
                    }
                    // ###END###{Scripting}
                }

                // ###BEGIN###{Look-Commander}
                // ###BEGIN###{!ComputerSelectorNoImages}
                x += '<div style="overflow-y:auto;position:absolute;top:216px;left:4px;right:4px;bottom:' + bottomButtonsHeight + 'px">';
                // ###END###{!ComputerSelectorNoImages}
                // ###BEGIN###{ComputerSelectorNoImages}
                x += '<div style="overflow-y:auto;position:absolute;top:4px;left:4px;right:4px;bottom:' + bottomButtonsHeight + 'px">';
                // ###END###{ComputerSelectorNoImages}
                // ###END###{Look-Commander}
                // ###BEGIN###{!Look-Commander}
                x += '<div style="overflow-y:auto;position:absolute;top:4px;left:4px;right:4px;bottom:' + bottomButtonsHeight + 'px">';
                if (currentcomputer['name']) x += addComputerDetailsEntry("Friendly Name", EscapeHtml(decodeURIComponent(currentcomputer['name'])));
                // ###END###{!Look-Commander}
                x += addComputerDetailsEntry("Host Name", decodeURIComponent(currentcomputer['host']));

                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer == null) {
                // ###END###{MeshServerConnect}
                if (currentcomputer['user'] != '*') {
                    x += addComputerDetailsEntry("Authentication", "Digest / " + EscapeHtml(decodeURIComponent(currentcomputer['user'])));
                } else {
                    if (currentcomputer['pass'] == '') {
                        x += addComputerDetailsEntry("Authentication", "Kerberos");
                    } else {
                        x += addComputerDetailsEntry("Authentication", "Kerberos / " + EscapeHtml(decodeURIComponent(currentcomputer['pass'])));
                    }
                }
                x += addComputerDetailsEntry("Security", ((currentcomputer['tls'] == 0)?"None":"TLS Security"));
                if (currentcomputer['tags']) { x += addComputerDetailsEntry("Group Name", EscapeHtml(decodeURIComponent(currentcomputer['tags']))); }
                // ###BEGIN###{MeshServerConnect}
                } else {
                    if (currentcomputer['tags']) { x += addComputerDetailsEntry("Device Group", EscapeHtml(decodeURIComponent(currentcomputer['tags']))); }
                    if (currentcomputer['conn']) {
                        var cn = [];
                        if ((currentcomputer['conn'] & 1) != 0) cn.push('Agent');
                        if ((currentcomputer['conn'] & 2) != 0) cn.push('CIRA');
                        else if ((currentcomputer['conn'] & 4) != 0) cn.push('Direct');
                        else if ((currentcomputer['conn'] & 8) != 0) cn.push('Relay');
                        x += addComputerDetailsEntry("Connectivity", cn.join(', '));
                    }
                }
                // ###END###{MeshServerConnect}

                if (currentcomputer['ver']) {
                    var mode = '';
                    if (currentcomputer['pstate'] == 2) { mode = "ACM"; if (currentcomputer['pmode'] == 2) mode = "CCM"; }
                    if (mode != '') mode = ' / ' + mode;
                    x += addComputerDetailsEntry("Intel&reg; AMT", "v" + currentcomputer['ver'] + mode);
                }
                if (currentcomputer['date']) { x += addComputerDetailsEntry("Last Connection", new Date(currentcomputer['date']).toDateString()); }
                if (currentcomputer['digestrealm']) {
                    // ###BEGIN###{ContextMenus}
                    x += '<div cm="' + NoBreak("Remove Realm...") + '#removeCurrentRealm(' + currentcomputer['h'] + ')">';
                    // ###END###{ContextMenus}
                    x += addComputerDetailsEntry("Digest Realm", '<span style=font-size:x-small>' + currentcomputer['digestrealm'] + '</span><br /><span style=margin-left:5px><a style=cursor:pointer;font-size:10px;color:blue onclick=removeCurrentRealm(' + currentcomputer['h'] + ')><u>' + "Remove Realm" + '</u></a></span>');
                    // ###BEGIN###{ContextMenus}
                    x += '</div>';
                    // ###END###{ContextMenus}
                }
                // ###BEGIN###{Mode-NodeWebkit}
                // ###BEGIN###{Certificates}
                if (currentcomputer['tlscerthash']) {
                    if (currentcomputer['tlscert']) {
                        // ###BEGIN###{ContextMenus}
                        x += '<div cm="' + NoBreak("View Certificate...") + '#viewCurrentPinCertificate(' + currentcomputer['h'] + ')|' + NoBreak("Remove Pinning...") + '#removeCurrentPinCertificate(' + currentcomputer['h'] + ')">';
                        // ###END###{ContextMenus}
                        x += addComputerDetailsEntry("TLS Certificate", '<span title="Cert hash: ' + currentcomputer['tlscerthash'] + '">' + "Pinned to specific certificate" + '</span><br /><span style=margin-left:5px><a style=cursor:pointer;font-size:10px;color:blue onclick=viewCurrentPinCertificate(' + currentcomputer['h'] + ')><u>' + "Show Certificate" + '</u></a> <a style=cursor:pointer;font-size:10px;color:blue onclick=removeCurrentPinCertificate(' + currentcomputer['h'] + ')><u>' + "Remove Pinning" + '</u></a></span>');
                        // ###BEGIN###{ContextMenus}
                        x += '</div>';
                        // ###END###{ContextMenus}
                    } else {
                        // ###BEGIN###{ContextMenus}
                        x += '<div cm="' + NoBreak("Remove Pinning...") + '#removeCurrentPinCertificate(' + currentcomputer['h'] + ')">';
                        // ###END###{ContextMenus}
                        x += addComputerDetailsEntry("TLS Certificate", '<span title="Cert hash: ' + currentcomputer['tlscerthash'] + '">' + "Pinned to specific certificate" + '</span><br /><span style=margin-left:5px><a style=cursor:pointer;font-size:10px;color:blue onclick=removeCurrentPinCertificate(' + currentcomputer['h'] + ')><u>' + "Remove Pinning" + '</u></a></span>');
                        // ###BEGIN###{ContextMenus}
                        x += '</div>';
                        // ###END###{ContextMenus}
                    }
                }
                // ###END###{Certificates}
                // ###END###{Mode-NodeWebkit}
                x += '</div>';

            }
            QH('id_computerDetails', x + bottomButtons + '</div>');
            computerSelect();
        }

        // ###BEGIN###{Look-Commander}
        // ###BEGIN###{!ComputerSelectorNoImages}
        function showIconSelector() {
            if (xxdialogMode) return;
            var x = '<br><div style=display:inline-block;width:40px></div>';
            x += '<div style=display:inline-block class=i1 onclick=setIcon(1)></div>';
            x += '<div style=display:inline-block class=i2 onclick=setIcon(2)></div>';
            x += '<div style=display:inline-block class=i3 onclick=setIcon(3)></div>';
            x += '<div style=display:inline-block class=i4 onclick=setIcon(4)></div>';
            x += '<div style=display:inline-block class=i5 onclick=setIcon(5)></div>';
            x += '<div style=display:inline-block class=i6 onclick=setIcon(6)></div>';
            setDialogMode(11, "Icon Selection", 0, null, x);
            QV('id_dialogclose', true);
        }

        function setIcon(icon) {
            setDialogMode(0);
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) { meshCentralServer.send({ action: 'changedevice', nodeid: currentcomputer._id, icon: icon }); return; }
            // ###END###{MeshServerConnect}
            currentcomputer['icon'] = icon;
            // ###BEGIN###{ComputerSelector-Local}
            saveComputers();
            // ###END###{ComputerSelector-Local}
            updateComputerList();
        }
        // ###END###{!ComputerSelectorNoImages}
        // ###END###{Look-Commander}

        // ###BEGIN###{Mode-NodeWebkit}
        // ###BEGIN###{ContextMenus}
        // ###BEGIN###{Certificates}
        function viewCurrentPinCertificate(h) {
            if (xxdialogMode) return;
            var c = null;
            for (var x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { c = computerlist[x]; } }
            var cert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(hex2rstr(c['tlscert'])));
            var commonName = cert.subject.getField('CN').value;
            var fingerprint = '', fingerprint2 = forge.md.sha1.create().update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()).digest().toHex().toUpperCase();
            for (i = 0; i < fingerprint2.length; i++) { if ((i != 0) && (i % 2 == 0)) { fingerprint += ':'; } fingerprint += fingerprint2.substring(i, i + 1); }
            var x = '<img src=images-commander/cert1.png style=float:right height=32 width=32 />';
            x += 'This certificate is pinned to computer ' + c['name'] + '. When connecting, if this certificate is received the connection will allowed. Hit delete button to un-pin.<br>';
            // ###BEGIN###{FileSaver}
            //x += addHtmlValue("Certificate", c.X509Certificate.length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=downloadCert(' + h + ')>' + "Download" + '</a>');
            // ###END###{FileSaver}
            // ###BEGIN###{!FileSaver}
            //x += addHtmlValue("Certificate", c.X509Certificate.length + " bytes");
            // ###END###{!FileSaver}
            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Certificate Subject" + '</i></div><br>';
            for (var i in xxCertSubjectNames) { var a = cert.subject.getField(i); if (a) { x += addHtmlValue(xxCertSubjectNames[i], EscapeHtml(a.value)); } }
            x += addHtmlValueNoTitle("Fingerprint", fingerprint.substring(0,29) + '<br />' + fingerprint.substring(30));
            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Issuer Certificate" + '</i></div><br>';
            for (var i in xxCertSubjectNames) { var a = cert.issuer.getField(i); if (a) { x += addHtmlValue(xxCertSubjectNames[i], EscapeHtml(a.value)); } }
            setDialogMode(11, "Certificate - " + EscapeHtml(commonName), 5, function (b) { if (b == 2) { removeCurrentPinCertificateEx(2, h); } }, x);
        }

        function removeCurrentPinCertificate(h) {
            if (xxdialogMode) return;
            setDialogMode(11, "Certificate Pinning", 3, removeCurrentPinCertificateEx, "Remove certificate pinning for selected computer?", h);
        }

        function removeCurrentPinCertificateEx(button, h) {
            var c = null;
            for (var x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { c = computerlist[x]; } }
            if (c['tlscert']) delete c['tlscert'];
            if (c['tlscerthash']) delete c['tlscerthash'];
            storeCertPinning(c['host'], null);
            saveComputers();
            updateComputerList();
        }
        // ###END###{Certificates}
        // ###END###{ContextMenus}
        // ###END###{Mode-NodeWebkit}

        function removeCurrentRealm(h) {
            if (xxdialogMode) return;
            setDialogMode(11, "Digest Realm", 3, removeCurrentRealmEx, "Remove Digest Realm pinning for selected computer?", h);
        }

        function removeCurrentRealmEx(button, h) {
            var c = null;
            for (var x = 0; x < computerlist.length; x++) { if (computerlist[x]['h'] == h) { c = computerlist[x]; } }
            if (c['digestrealm']) delete c['digestrealm'];
            saveComputers();
            updateComputerList();
        }

        // ###BEGIN###{ComputerSelector-Local}
        function saveComputers() {
            if (urlvars['host']) return;
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) return;
            // ###END###{MeshServerConnect}
            // ###BEGIN###{Mode-NodeWebkit}
            const crypto = require('crypto');
            crypto.randomBytes(256, function(err, buf) {
                if (err) throw err; // Add trivial security, not intended to be real security. This just avoids storing data in plain text, but it's almost the same.
                var computerlist2 = JSON.parse(JSON.stringify(computerlist));
                for (var i in computerlist2) { delete computerlist2[i]['tlscert2']; delete computerlist2[i]['tlscerthash2']; } // Clean up the list
                var k = buf.toString('hex'), cipher = crypto.createCipher('aes-256-ctr', k), crypted = cipher.update(JSON.stringify(computerlist2), 'utf8', 'hex');
                crypted += cipher.final('hex');
                try { localStorage.setItem('computers', k + crypted); } catch (ex) { }
            });
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            try { localStorage.setItem('computers', JSON.stringify(computerlist)); } catch (ex) { }
            // ###END###{!Mode-NodeWebkit}
        }

        function loadComputers() {
            if (urlvars['host']) return;
            // ###BEGIN###{Mode-NodeWebkit}
            var ctext = null;
            try { ctext = localStorage.getItem('computers'); } catch (ex) { }
            if (ctext) {
                try { computerlist = JSON.parse(ctext); } catch (e) {
                    if (ctext.length > 512) { // Add trivial security, not intended to be real security. This just avoids storing data in plain text, but it's almost the same.
                        var crypto = require('crypto'), k = ctext.substring(0, 512), crypted = ctext.substring(512), decipher = crypto.createDecipher('aes-256-ctr', k), dec = decipher.update(crypted, 'hex', 'utf8');
                        dec += decipher.final('utf8');
                        try { computerlist = JSON.parse(dec); } catch (e) { computerlist = []; }
                        var pins = getCertPinnings();
                        for (var i in computerlist) {
                            computerlist[i].checked = false;
                            // Add stored certificate pinning.
                            if ((computerlist[i]['tlscerthash'] == null) && (pins[computerlist[i]['host']] != null)) { computerlist[i]['tlscerthash'] = pins[computerlist[i]['host']]; }
                            delete computerlist[i]['tlscert2'];
                            delete computerlist[i]['tlscerthash2'];
                        }
                    }
                }
            }
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            var ctext = null;
            try { ctext = localStorage.getItem('computers'); } catch (ex) { }
            if (ctext) { try { computerlist = JSON.parse(ctext); } catch (e) { computerlist = []; } }
            // ###END###{!Mode-NodeWebkit}
            updateComputerList();
            // ###BEGIN###{ComputerSelectorScanner}
            // ###BEGIN###{Mode-NodeWebkit}
            globalAmtScanner.performScan();
            // ###END###{Mode-NodeWebkit}
            // ###END###{ComputerSelectorScanner}
        }
        // ###END###{ComputerSelector-Local}

        function computerConnect(e, h, m, skipPass) {
            if (xxdialogMode) return;
            // ###BEGIN###{Mode-NodeWebkit}
            if ((m == 100) || (e && (e.shiftKey == true))) {
                // Launch a new instance of MeshCommander
                var adder = '';
                // ###BEGIN###{Desktop}
                if (m == 1) { adder = '&kvm=1'; }
                if (m == 2) { adder = '&kvmfull=1'; }
                if (m == 3) { adder = '&kvmonly=1'; }
                // ###END###{Desktop}
                // ###BEGIN###{Terminal}
                if (m == 4) { adder = '&sol=1'; }
                // ###END###{Terminal}
                var username = currentcomputer['user'];
                if (username == '') { username = 'admin'; }
                require('nw.gui').Window.open(window.location.href + '?host=' + currentcomputer['host'] + '&user=' + username + '&pass=' + currentcomputer['pass'] + '&tls=' + currentcomputer['tls'] + adder, { 'icon': 'favicon.png', 'toolbar': false, 'frame': true, 'width': 970, 'min_width': 970, 'height': 760, 'min_height': 640 });
                //require('child_process').exec('nw.exe -host:' + decodeURIComponent(currentcomputer['host']) + ' -user:' + decodeURIComponent(currentcomputer['user']) + ' -pass:' + decodeURIComponent(currentcomputer['pass']) + ((currentcomputer['tls']==1)?' -tls':''), function (error, stdout, stderr) { });
                return;
            }
            // ###END###{Mode-NodeWebkit}
            if (e) haltEvent(e);
            computerSelect(null, h);
            if (currentcomputer == null) return;
            if ((currentcomputer['user'] != '*') && (currentcomputer['pass'] == '')) {
                if (skipPass === true) { computerConnectLogin(9, m); return; }
                // Query for the login password
                var x = '<br>Enter the login password for ' + EscapeHtml(currentcomputer['name'] ? currentcomputer['name'] : currentcomputer['host']) + '.<br><br>';
                x += '<div style=height:26px><input id=d11connectUser onkeyup=computerConnectUpdateLogin() style=float:right;width:200px value="' + currentcomputer['user'] + '"><div>' + "Username" + '</div></div>';
                x += '<div style=height:26px><input id=d11connectPass onkeyup=computerConnectUpdateLogin(event) type=password style=float:right;width:200px><div>' + "Password" + '</div></div>';
                setDialogMode(11, "Login Credentials", 3, computerConnectLogin, x);
                Q('d11connectPass').focus();
                computerConnectUpdateLogin();
            } else {
                // Go ahead and connect
                computerConnectLogin(0, m);
            }
        }

        function computerConnectUpdateLogin(e) {
            var ok = (Q('d11connectUser').value.length > 0) && (passwordcheck(Q('d11connectPass').value));
            QE('idx_dlgOkButton', ok);
            if ((e != undefined) && (e.keyCode == 13) && (ok == true)) { setDialogMode(0); computerConnectLogin(1, xxdialogTag); }
        }

        // If the user is prompted for a user/pass, we should not re-prompt after a certificate validation prompt.
        var skipPassUser = null;
        var skipPassPass = null;
        function computerConnectLogin(button, m) {
            var user = decodeURIComponent(currentcomputer['user']);
            var pass = decodeURIComponent(currentcomputer['pass']);
            if (button == 1) { user = Q('d11connectUser').value; pass = Q('d11connectPass').value; }
            if (button == 9) { user = skipPassUser; pass = skipPassPass; }
            skipPassUser = user;
            skipPassPass = pass;

            // Go ahead and connect
            var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
            if (user == '') { user = 'admin'; } // Default to admin if not specified.
            connect(ports.host, ports.http, user, pass, currentcomputer['tls'], function (mtag) {
                // ###BEGIN###{Mode-NodeWebkit}
                // If the fingerprint is set but not the certificate, set the cert.
                if (wsstack.comm.xtlsCertificate && (currentcomputer['tlscert'] == null) && (wsstack.comm.xtlsFingerprint == currentcomputer['tlscerthash'])) {
                    currentcomputer['tlscert'] = wsstack.comm.xtlsCertificate.raw.toString('hex');
                    updateComputerDetails();
                }
                // ###END###{Mode-NodeWebkit}
                // ###BEGIN###{Desktop}
                if (mtag == 1) { go(14); connectDesktop(); } // Go directly to remote desktop (1)
                if ((mtag == 2) || (mtag == 3)) { connectDesktop(); } // Go remote desktop fullscreen (2) and only remote desktop (3)
                // ###END###{Desktop}
                // ###BEGIN###{Terminal}
                if (mtag == 4) { go(13); connectTerminal(); } // Go directly to terminal (4)
                // ###END###{Terminal}
            }, m);
            if (m == 1) { go(14); }
            if ((m == 2) || (m == 3)) { go(14); deskToggleFull(m == 3); }
            if (m == 4) { go(13); }
        }

        function computerSelect(e, h) {
            if (h && ((currentcomputer == null) || (currentcomputer.h !== h))) { currentcomputer = getComputer(h); updateComputerDetails(); }
            for (var y in computerlist) {
                var computer = computerlist[y], sel = (currentcomputer != null && computer['h'] == currentcomputer['h']);
                QS('CI-' + computer['h'])['background-color'] = sel ? '#a0a0a0' : '#c9c9c9';
                Q('LCX-' + computer['h']).classList.remove('g1');
                Q('LCX-' + computer['h']).classList.remove('g1s');
                Q('RCX-' + computer['h']).classList.remove('g2');
                Q('RCX-' + computer['h']).classList.remove('g2s');
                Q('LCX-' + computer['h']).classList.add(sel?'g1s':'g1');
                Q('RCX-' + computer['h']).classList.add(sel?'g2s':'g2');
            }
        }

        function getComputer(h) { for (var i in computerlist) { if (computerlist[i]['h'] == h) return computerlist[i]; } return null; }

        // ###BEGIN###{Scripting}
        function mscript_showComputerScriptOutput(h) {
            if (xxdialogMode) return;
            var computer = getComputer(h);
            computer.consoledialog = 'scriptOutputArea';
            var name = computer['name'];
            if (!name) name = computer['host'];
            var v = '<textarea id=scriptOutputArea style=width:100%;height:150px;resize:vertical spellcheck=false readonly></textarea>';
            setDialogMode(11, "Script Output - " + name, 5, mscript_showComputerScriptOutputOk, v, computer);
            Q('scriptOutputArea').value = EscapeHtml(computer['consolemsgs']);
        }

        function mscript_showComputerScriptOutputOk(button, computer) {
            computer.consoledialog = undefined;
            if (button == 2) {
                if (computer.scriptstate) {
                    computer['consolemsgs'] = '';
                } else {
                    delete computer['consolemsgs'];
                    delete computer['consolemsg'];
                }
                saveComputers();
                updateComputerDetails();
            }
        }

        function mscript_runScriptDlg() {
            if (computersRunningScripts > 0) {
                // Stop all scripts
                for (var y in computerlist) {
                    var computer = computerlist[y];
                    if (computer.scriptstate) { computer.scriptstate.stop(); computer.scriptstate = undefined; }
                }
                updateComputerList();
            } else {
                // Start a new script dialog box
                if (xxdialogMode || scriptstate) return;
                var clist = [];
                for (var y in computerlist) { if (computerlist[y].checked == true) { clist.push(computerlist[y]); } }
                if (clist.length == 0) { clist.push(currentcomputer); }
                setDialogMode(11, "Run Script", 3, mscript_runScriptDlgOk, '<br>' + format("Run a selected script on {0} computer(s)", clist.length) + '.<br><br><input id=mscriptopen type=file style=width:100% accept=".mescript">');
            }
        }

        function mscript_runScriptDlgOk(r) {
            if (r != 1) return;
            var x = Q('mscriptopen');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = mscript_onScriptReadNoPrompt;
            reader.readAsBinaryString(x.files[0]);
        }

        function mscript_onScriptReadNoPrompt(file) { mscript_onScriptRead(file, 1); }
        function mscript_onScriptRead(file, noprompt) {
            if (computersRunningScripts > 0) return;
            var x, clist = [];
            try { x = JSON.parse(file.target.result); } catch (e) {}
            if (x && x['mescript']) {
                onComputerChecked();
                for (var y in computerlist) { if (computerlist[y].checked == true) { clist.push(computerlist[y]); } }
                if (clist.length == 0) { clist.push(currentcomputer); }
                x.clist = clist;
                if (noprompt == 1) {
                    mscript_onScriptReadOk(0, x);
                } else {
                    setDialogMode(11, "Run Script", 3, mscript_onScriptReadOk, format("Run this script on {0} computer(s)?", clist.length), x);
                }
            }
        }

        function mscript_onScriptReadOk(button, tag) {
            var x = tag;

            // ###BEGIN###{CertificateManager}
            var tlsoptions = {};

            // Create a list of trusted certificates in PEM format
            var trustedCertStringsPem = [];
            for (var y in certificateStore) {
                var certificate = certificateStore[y];
                if (certificate['trusted'] == true) { trustedCertStringsPem.push('-----BEGIN CERTIFICATE-----\n' + certificate['certbin'] + '\n-----END CERTIFICATE-----\n'); }
            }
            tlsoptions.ca = trustedCertStringsPem;

            // Setup out console TLS authentication certificate
            var authcert = getTlsAuthCertificate();
            if (authcert != null) {
                tlsoptions.cert = forge.pki.certificateToPem(authcert['cert']);
                tlsoptions.key = forge.pki.privateKeyToPem(authcert['privateKey']);
            }
            // ###END###{CertificateManager}

            for (var y in x.clist) {
                var mscriptstate, computer = x.clist[y], startvars = { '_interactive':0 };
                // ###BEGIN###{Certificates}
                startvars['_certificates'] = 1;
                // ###END###{Certificates}
                // ###BEGIN###{Mode-Firmware}
                startvars['_mode'] = 'Firmware';
                // ###END###{Mode-Firmware}
                // ###BEGIN###{Mode-MeshCentral2}
                startvars['_mode'] = 'MeshCentral2';
                // ###END###{Mode-MeshCentral2}
                // ###BEGIN###{Mode-NodeWebkit}
                startvars['_mode'] = 'NodeWebkit';
                // ###END###{Mode-NodeWebkit}
                // ###BEGIN###{Mode-LMS}
                startvars['_mode'] = 'LMS';
                // ###END###{Mode-LMS}
                // ###BEGIN###{Mode-WebSite}
                startvars['_mode'] = 'WebSite';
                // ###END###{Mode-WebSite}
                if (x && x['mescript']) mscriptstate = script_setup(atob(x['mescript']), startvars);
                if (mscriptstate) {
                    mscriptstate.computer = computer;
                    var ports = portsFromHost(computer['host'], computer['tls']);
                    // ###BEGIN###{CertificateManager}
                    mscriptstate.wsstack = WsmanStackCreateService(ports.host, ports.http, decodeURIComponent(computer['user']), decodeURIComponent(computer['pass']), computer['tls'], tlsoptions);
                    // ###END###{CertificateManager}
                    // ###BEGIN###{!CertificateManager}
                    mscriptstate.wsstack = WsmanStackCreateService(ports.host, ports.http, decodeURIComponent(computer['user']), decodeURIComponent(computer['pass']), computer['tls']);
                    // ###END###{!CertificateManager}
                    mscriptstate.amtstack = AmtStackCreateService(mscriptstate.wsstack);
                    mscriptstate.onStep = mscript_updateScriptState;
                    mscriptstate.onConsole = mscript_console;

                    // Setup TLS checking
                    // ###BEGIN###{Mode-NodeWebkit}
                    if (NW_TlsSecurityMode == 0) { mscriptstate.wsstack.comm.xtlsFingerprint = 0; }
                    else { mscriptstate.wsstack.comm.xtlsFingerprint = computer['tlscerthash'] ? computer['tlscerthash'] : computer['tlscerthash2']; }
                    // ###END###{Mode-NodeWebkit}

                    computer['consolemsg'] = '';
                    computer['consolemsgs'] = '';
                    computer.scriptstate = mscriptstate;
                    computer.scriptstate.start(100);
                } else {
                    messagebox("Run Script", "Invalid script file.")
                    return;
                }
            }
            updateComputerList();
        }

        function mscript_updateScriptState(scriptstate) {
            if (scriptstate.state == 0) { scriptstate.computer.scriptstate = undefined; updateComputerList(); }
        }

        function mscript_console(msg, scriptstate) {
            scriptstate.computer['consolemsg'] = msg;
            scriptstate.computer['consolemsgs'] += (msg + '\r\n');
            if (scriptstate.computer.consoledialog) { Q(scriptstate.computer.consoledialog).value = scriptstate.computer['consolemsgs']; }
            QH('XI-' + scriptstate.computer['h'], msg);
        }

        function computerStopScript(e, h) {
            var computer = getComputer(h);
            if (computer.scriptstate) { computer.scriptstate.stop(); computer.scriptstate = undefined; }
            updateComputerList();
        }

        // ###END###{Scripting}

        //
        // MeshCentral Connection
        //
        // ###BEGIN###{MeshServerConnect}
        function showMeshCentralConnectDialog(showtoken) {
            if (xxdialogMode || meshCentralServer) return;
            var x = '<img src=\'images-commander/meshcentral50.png\' style=width:50px;height:50px;float:right></img><div>' + "Connect to a MeshCentral server and manage Intel&reg; AMT computers on that account." + '<div><br style=clear:both />';
            x += '<div style=height:26px><input id=meshserverurl value="" placeholder="sample.server.com:443" style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Server name" + '</div></div>';
            x += '<div style=height:26px><input id=meshserverhash value="" style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Certificate Hash" + '</div></div>';
            x += '<div style=height:26px><input id=meshserveruser value="" style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Username" + '</div></div>';
            x += '<div style=height:26px><input id=meshserverpass value="" type=password style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Password" + '</div></div>';
            if (showtoken) { x += '<div style=height:26px><input id=meshservertoken value="" style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Login Token" + '</div></div>'; }
            //x += '<div style=height:26px><input id=meshserverproxy value="" placeholder="proxy.com:123" style=float:right;width:250px onkeyup=showMeshCentralConnectDialogUpdate()><div>' + "Proxy" + '</div></div>';
            setDialogMode(11, "MeshCentral Connect", 3, showMeshCentralConnectDialogOk, x);
            try {
                if (localStorage.getItem('meshserverurl')) { Q('meshserverurl').value = localStorage.getItem('meshserverurl'); }
                if (localStorage.getItem('meshserverhash')) { Q('meshserverhash').value = localStorage.getItem('meshserverhash'); }
                if (localStorage.getItem('meshserveruser')) { Q('meshserveruser').value = localStorage.getItem('meshserveruser'); }
                //if (localStorage.getItem('meshserverproxy')) { Q('meshserverproxy').value = localStorage.getItem('meshserverproxy'); }
            } catch (ex) { }
            showMeshCentralConnectDialogUpdate();
        }

        function showMeshCentralConnectDialogUpdate() {
            QS('meshserverurl')['background-color'] = ((Q('meshserverurl').value.length > 0) ? 'white' : 'LightYellow');
            QS('meshserveruser')['background-color'] = ((Q('meshserveruser').value.length > 0) ? 'white' : 'LightYellow');
            QS('meshserverpass')['background-color'] = ((Q('meshserverpass').value.length > 0) ? 'white' : 'LightYellow');
            var token = true;
            try { token = (Q('meshservertoken').value.length > 0); } catch (ex) { }
            QE('idx_dlgOkButton', token && (Q('meshserverurl').value.length > 0) && (Q('meshserveruser').value.length > 0) && (Q('meshserverpass').value.length > 0));
        }

        function showMeshCentralConnectDialogOk() {
            try {
                localStorage.setItem('meshserverurl', Q('meshserverurl').value);
                localStorage.setItem('meshserverhash', Q('meshserverhash').value);
                localStorage.setItem('meshserveruser', Q('meshserveruser').value);
            } catch (ex) { }
            var pass = Q('meshserverpass').value;
            var token = null;
            try { token = Q('meshservertoken').value; } catch (ex) { }
            //try { localStorage.setItem('meshserverproxy', Q('meshserverproxy').value); } catch (ex) { }
            var serverUrl = Q('meshserverurl').value;
            if (serverUrl.indexOf('://') < 0) { serverUrl = ('wss://' + serverUrl); }
            serverUrl = new URL(serverUrl);
            var serverPort = parseInt(serverUrl.port);
            if (isNaN(serverPort) || serverPort == 0) { serverPort = 443; }
            meshCentralServer = CreateMeshCentralServer(serverUrl.hostname, serverPort, '/control.ashx', Q('meshserveruser').value, Q('meshserverpass').value, token, Q('meshserverhash').value);
            meshCentralServer.onStateChange = function (sender, state, cause, msg) {
                var askForToken = false;
                if (state == 0) {
                    // Disconnected
                    loadComputers();
                    // If the connection failed due to hash mismatch, prompt the user.
                    disconnect();
                    QH('id_computername', format("Remote Management Console v{0}", version));
                    if (cause == 'HashMatchFail') { showTlsCert(3, "Connected to MeshCentral server with unrecognized certificate. Click ok to accept & connect.", meshCentralServer.xtlsCertificate, meshCentralServer.password, meshCentralHashRetry); }
                    else if ((cause == 'noauth') && (msg == 'tokenrequired')) { askForToken = true; }
                    else if (cause == 'noauth') { setDialogMode(11, "MeshCentral Connection", 1, null, "Invalid username or password."); }
                    meshCentralServer = null;
                } else if (state == 1) {
                    // Connecting
                    currentcomputer = null;
                    computerlist = [];
                    QH('id_computername', 'Remote Management Console v' + version + ', Connecting to ' + meshCentralServer.host + '...');
                } else if (state == 3) {
                    // Connected
                    currentcomputer = null;
                    computerlist = meshCentralServer.computerlist;
                    meshCentralServer.xconnected = true;
                    QH('id_computername', 'Remote Management Console v' + version + ', Server: ' + meshCentralServer.host);
                }
                updateComputerList();
                NW_SetupMainMenu(currentView);

                if (askForToken) {
                    // Ask for 2-factor token and try again
                    showMeshCentralConnectDialog(true);
                    Q('meshserverpass').value = pass;
                    Q('meshservertoken').focus();
                    showMeshCentralConnectDialogUpdate();
                }
            }
            meshCentralServer.onNodeChange = function (sender, node) {
                //computerlist = meshCentralServer.computerlist;
                updateComputerList();
            }
            setDialogMode(0);
            meshCentralServer.connect();
        }

        // The user accepted the MeshCentral server hash, set it and try to connect again.
        function meshCentralHashRetry(b, args) {
            try { localStorage.setItem('meshserverhash', args.c.fingerprint.split(':').join('').toLowerCase()); } catch (ex) { }
            showMeshCentralConnectDialog();
            Q('meshserverpass').value = args.m; // Set the retry password
            showMeshCentralConnectDialogOk();
        }

        function meshCentralDisconnect() {
            if (meshCentralServer == null) return;
            meshCentralServer.disconnect();
            meshCentralServer = null;
            currentcomputer = null;
            updateComputerList();
        }
        // ###END###{MeshServerConnect}

        // ###BEGIN###{ComputerSelectorScanner}
        // ###BEGIN###{Mode-NodeWebkit}

        //
        // Network scan
        //

        var globalAmtScanner = CreateAmtScanner(amtScanChangePresence);
        var globalAmtScannerResults = null;

        function showScanDialog() {
            if (xxdialogMode) return;
            var x = "Enter a range of IP addresses to scan for Intel AMT devices." + '<br /><br />';
            x += '<div style=height:20px><div style=float:right;width:260px;overflow:hidden><input id=idx_iprange style=width:204px placeholder="192.168.0.0/16" onkeyup=showScanDialogUpdate()></input><input id=idx_iprangebutton type=button value=Scan onclick=amtScanStartScan()></input></b></div><div>' + "IP Range" + '</div></div>';
            x += '<br /><div id=idx_results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
            setDialogMode(11, "Scan for Intel&reg; AMT devices", 3, showScanDialogOk, x);
            QH('idx_results', '<div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>' + "Sample IP range values" + '<br />192.168.0.100<br />192.168.0.0/16<br />192.168.0.1-192.168.0.100</div>');
            try { Q('idx_iprange').value = localStorage.getItem('scanrange'); } catch (ex) { }
            showScanDialogUpdate();
        }

        function showScanDialogUpdate() {
            QS('idx_iprange')['background-color'] = ((Q('idx_iprange').value.length > 0) ? 'white' : 'LightYellow');
            QE('idx_iprangebutton', Q('idx_iprange').value.length > 0);
            amtScanCheckbox();
        }

        // Populate the Intel AMT scan dialog box with the result of the RMCP scan
        function amtScanResult(scanner, result) {
            if ((xxdialogMode == undefined) || (!Q('idx_iprange'))) return;
            if (result == null) {
                // If no results where found, display a nice message
                QH('idx_results', '<div style=width:100%;text-align:center;margin-top:12px>Scan returned no results.</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.0.0/16<br />192.167.0.1-192.168.0.100</div>');
            } else {
                // Add the new result to the scan results dialog box
                var x = '', str = '<b>' + result.rinfo.address + '</b> - v' + result.ver;
                if (globalAmtScannerResults == null) { globalAmtScannerResults = {}; QH('idx_results', ''); }
                globalAmtScannerResults[result.rinfo.address] = result;
                if (result.state == 2) { if (result.tls == 1) { str += ' with TLS.'; } else { str += ' without TLS.'; } } else { str += ' not activated.'; }
                x += '<div style=margin-bottom:2px>';
                x += '<div class=j1 style=height:24px;float:left;background-color:white></div>';
                x += '<div class=g1 style=height:24px;float:left></div><div class=g2 style=height:24px;float:right></div><div style=height:24px;width:100%;background-color:#c9c9c9><div><div style=display:inline-block;margin-right:5px><input class=DevScanCheckbox tag="' + result.rinfo.address + '" type=checkbox onclick=amtScanCheckbox() /></div><div style=display:inline-block;margin-left:5px>' + str + '</div></div></div></div>';
                QA('idx_results', x);
            }
        }

        function amtScanStartScan() {
            var ip_range = Q('idx_iprange').value;
            try { localStorage.setItem('scanrange', ip_range); } catch (ex) { }
            globalAmtScannerResults = null;
            if (globalAmtScanner.performRangeScan('1', ip_range, amtScanResult) == false) {
                // The scan could not occur because of an error. Likely the user range was invalid.
                x = '<div style=width:100%;text-align:center;margin-top:12px>' + "Unable to scan this address range." + '</div><div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>' + "Sample IP range values" + '<br />192.168.0.100<br />192.168.0.0/16<br />192.167.0.1-192.168.0.100</div>';
            } else {
                // Show scanning...
                QH('idx_results', '<div style=width:100%;text-align:center;margin-top:12px>' + "Scanning..." + '</div>');
            }
        }

        // Called when a scanned computer is checked or unchecked.
        function amtScanCheckbox() {
            var elements = document.getElementsByClassName('DevScanCheckbox'), checkcount = 0;
            for (var i in elements) { if (elements[i].checked) checkcount++; }
            QE('idx_dlgOkButton', checkcount > 0);
        }

        // Called when the OK button is pressed on the scan dialog
        function showScanDialogOk() {
            var elements = document.getElementsByClassName('DevScanCheckbox');
            for (var i in elements) {
                if (elements[i].checked) {
                    var ipaddr = elements[i].getAttribute('tag');
                    var result = globalAmtScannerResults[ipaddr];
                    computerlist.push({ 'h': Math.random(), 'name': ipaddr, 'host': ipaddr, 'tags': '', 'user': 'admin', 'pass': '', 'tls': result.tls, 'ver': result.ver });
                }
                saveComputers();
                updateComputerList();
            }
        }

        // Called by the scanner to change Intel AMT presense state
        function amtScanChangePresence(h, presence) {
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) return;
            // ###END###{MeshServerConnect}
            var element = Q('SS-' + h);
            if (element) { element.style['background-color'] = presence ? 'green' : 'red'; }

            // ###BEGIN###{Look-Commander}
            if (presence) { Q('SI-' + h).classList.remove('gray'); } else { Q('SI-' + h).classList.add('gray'); }
            // ###END###{Look-Commander}

            // If the computer that was updated is the current computer, update the details.
            if (currentcomputer && (currentcomputer.h == h)) { updateComputerDetails(); }
        }

        // Called when used clicks the "Scan for presense" menu option
        function NW_AmtScanMenu() {
            try { localStorage.setItem('scanForComputers', NW_AmtScanMenuItem.checked); } catch (ex) { }
            if (NW_AmtScanMenuItem.checked == true) { globalAmtScanner.start(); } else { globalAmtScanner.stop(); }
            updateComputerList();
        }

        // ###END###{Mode-NodeWebkit}
        // ###END###{ComputerSelectorScanner}

// ###END###{ComputerSelector}

// ###BEGIN###{ContextMenus}
        function handleContextMenu(e) {
            hideContextMenu();
            if (xxdialogMode) return;
            // ###BEGIN###{ComputerSelector}
            toolmenuclick(-1);
            // ###END###{ComputerSelector}
            var cm = document.elementFromPoint(e.pageX, e.pageY);
            while (cm && cm != null && cm.getAttribute('cm') == null) { cm = cm.parentElement; }
            if (cm && cm != null && cm.getAttribute('cm') != null) {
                var x = '', menus = cm.getAttribute('cm').split('|');
                if (cm.getAttribute('class') == 'computeritem') cm.click();
                for (var i in menus) {
                    if (menus[i] == '-') {
                        x += '<hr style="border:1px solid lightgray" />';
                    } else {
                        var menus2 = menus[i].split('#');
                        x += '<div class=cmtext onclick=\"hideContextMenu();' + menus2[1] + '\"><b>' + menus2[0] + '</b></div>';
                    }
                }
                QS('contextMenu').top = e.pageY + 'px';
                QS('contextMenu').left = e.pageX + 'px';
                QH('contextMenu', x);
                QV('contextMenu', true);
                haltEvent(e);
                return false;
            }
        }

        function hideContextMenu() { QV('contextMenu', false); }
// ###END###{ContextMenus}

        //
        // BOTTOM INFORMATION STRING
        //

// ###BEGIN###{VersionWarning}
        // Returns true if Intel AMT needs to be updated
        function checkAmtVersion(version) {
            var vSplit = version.split('.');
            var v1 = parseInt(vSplit[0]);
            var v2 = parseInt(vSplit[1]);
            var v3 = parseInt(vSplit[2]);
            var vx = ((v2 * 1000) + v3);
            var ok = 0;

            if ((v1 <= 5) || (v1 >= 12)) { ok = 1; } // Intel AMT less then v5 and v12 and beyond, all ok.
            else if ((v1 == 6) && (vx >= 2061)) { ok = 1; } // 1st Gen Core
            else if ((v1 == 7) && (vx >= 1091)) { ok = 1; } // 2st Gen Core
            else if ((v1 == 8) && (vx >= 1071)) { ok = 1; } // 3st Gen Core
            else if ((v1 == 9)) { if ((v2 < 5) && (vx >= 1041)) { ok = 1; } else if (vx >= 5061) { ok = 1; } } // 4st Gen Core
            else if ((v1 == 10) && (vx >= 55)) { ok = 1; } // 5st Gen Core
            else if (v1 == 11) {
                if ((v2 < 5) && (vx >= 25)) { ok = 1; } // 6st Gen Core
                else if (vx >= 6027) { ok = 1; } // 7st Gen Core
            }
            return (ok == 0);
        }
// ###END###{VersionWarning}

        function processSystemVersion(stack, name, responses, status) {
            if (status == 200 || status == 400) {
                var v;
                if (status == 200) {
                    //amtlogicalelements = responses;
                    amtlogicalelements = [];
                    if (responses != null) {
                        if (responses['CIM_SoftwareIdentity'] != null && responses['CIM_SoftwareIdentity'].responses != null) {
                            amtlogicalelements = responses['CIM_SoftwareIdentity'].responses;
                            if (responses['AMT_SetupAndConfigurationService'] != null && responses['AMT_SetupAndConfigurationService'].response != null) {
                                amtlogicalelements.push(responses['AMT_SetupAndConfigurationService'].response);
                            }
                        }
                    }
                    if (amtlogicalelements.length == 0) { console.error('ERROR: Could not get Intel AMT version.'); disconnect(); return; } // Could not get Intel AMT version, disconnect();
                    v = getInstance(amtlogicalelements, 'AMT')['VersionString'];
                } else {
                    v = stack.wsman.comm.amtVersion;
                    if (!v) { errcheck(400, stack); return; }
                }
                amtversion = parseInt(v.split('.')[0]);
                amtversionmin = parseInt(v.split('.')[1]);

                // If this is Intel AMT 16 or higher, boost the stack speed by allowing HTTP pipelining.
                //if (amtversion > 15) {
                    //stack.MaxActiveEnumsCount = 2;
                    //stack.wsman.comm.MaxActiveAjaxCount = 2;
                //}

                // ###BEGIN###{Mode-NodeWebkit}
                // Perform Intel ME authentication if available.
                if ((amtversion >= 15) && (wsstack.comm.xtlsCertificate != null)) {
                    stack.amtauthnonce = require('crypto').randomBytes(20).toString('base64');
                    stack.AMT_GeneralSettings_AMTAuthenticate(stack.amtauthnonce, function (stack, name, response, status) {
                        //console.log('AMTAuthenticate', status, response);
                        //status = 200;
                        //response = JSON.parse('{"Header":{"To":"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous","RelatesTo":"15","Action":"http://intel.com/wbem/wscim/1/amt-schema/1/AMT_GeneralSettings/AMTAuthenticateResponse","MessageID":"uuid:00000000-8086-8086-8086-00000000008E","ResourceURI":"http://intel.com/wbem/wscim/1/amt-schema/1/AMT_GeneralSettings","Method":"AMTAuthenticate"},"Body":{"Nonce":"s5PzXOyJqlPwnE/FJ1Imk2tLc2s=","UUID":"465A544C39335830B0304A51465A544C","FQDN":"","FWVersion":"15.0.10.7000","AMTSVN":1,"Signature":"cT4DpT2VpDi0jq+3tIswntXIIitCQV6QxMbXMZryob7RYRyazW9YFKrX5nfu0tPpTqLEP9P+C8pVT4ZngU1TIrn2ptVw/xCKmOn56Y62U0Gv+fQSG1+AJFRej+W7Clv4","LengthOfCertificates":[602,638,631,708],"Certificates":"MIICVjCCAd2gAwIBAgIQSsxzEcw7W5elVuRWfkbN1zAKBggqhkjOPQQDAzAeMRwwGgYDVQQDDBNDU01FIFRHTCBBTVQgIDAxU0RFMB4XDTIwMDcyMzAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowFTETMBEGA1UEAwwKQU1UIFdTLU1BTjB2MBAGByqGSM49AgEGBSuBBAAiA2IABOiUImnj9foD828QWknCF47SuIhwKn+AzhcgPz7IaUb/Z9KTPn57VfxahHBObijKRodtcxao0Jip/0sM3wbXkHvF03BLdxP6/ab5uMYLH+ZDjdlwC69qkjQtXciIzml8u6OB6DCB5TAfBgNVHSMEGDAWgBS4jxQZFu/qvArLmfxFoa+HO3ZPhjAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEB/wQEAwIGgDCBoAYDVR0fBIGYMIGVMIGSoEqgSIZGaHR0cHM6Ly90c0RFLmludGVsLmNvbS9jb250ZW50L09uRGllQ0EvY3Jscy9PbkRpZV9DQV9DU01FX0luZGlyZWN0LmNybKJEpEIwQDEmMCQGA1UECwwdT25EaWUgQ0EgQ1NNRSBJbnRlcm1lZGlhdGUgQ0ExFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwMlkcpHt5ydDt2hmnF+pJxLzH6oF3K2XPviuudyQ8DtHfuziWXgI7t2KS/Y5tOFEAAjBxLW0MkEcpDlsKNS0ASNxOhi6neEEQaxT93EJh3J/Z0SU8qYdE2/qtfe087XhCvlowggJ6MIICAaADAgECAgUBBBwAIDAKBggqhkjOPQQDAzAjMSEwHwYDVQQDDBhDU01FIFRHTCBTVk4wMSBLZXJuZWwgREUwHhcNMjAwNzIzMDAwMDAwWhcNNDkxMjMxMjM1OTU5WjAeMRwwGgYDVQQDDBNDU01FIFRHTCBBTVQgIDAxU0RFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAES/XBgK8rDlDycUzCocI1TrrrcQzD2Okq2BJhfqSg6MKxRMyei903Ewl94yl+tFsWoLuPiZDVE/bfxJghTynuGxk38YI8Qn8L3mPL+ahh3tSxWxC3kdszrU9dgObLF+2Io4IBCDCCAQQwHwYDVR0jBBgwFoAUzxraD/dMy5Zf2FiUKGctnPWwk30wHQYDVR0OBBYEFLiPFBkW7+q8CsuZ/EWhr4c7dk+GMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgIEMIGgBgNVHR8EgZgwgZUwgZKgSqBIhkZodHRwczovL3RzREUuaW50ZWwuY29tL2NvbnRlbnQvT25EaWVDQS9jcmxzL09uRGllX0NBX0NTTUVfSW5kaXJlY3QuY3JsokSkQjBAMSYwJAYDVQQLDB1PbkRpZSBDQSBDU01FIEludGVybWVkaWF0ZSBDQTEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTAKBggqhkjOPQQDAwNnADBkAjBiU4sHamrnSkvkwpTbVJah30CSGycVSwlUCUnXxFBFcCmXQeuXdElJiXhZyO5CQf8CMBxnQghoKlmUCKhzEYHjDMdXAKJcIapz6ksRDuYycxOlEpyBjei5tU5Nq16qDdt0njCCAnMwggH5oAMCAQICAQEwCgYIKoZIzj0EAwMwGjEYMBYGA1UEAwwPQ1NNRSBUR0wgUk9NIERFMB4XDTIwMDcyMzAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowIzEhMB8GA1UEAwwYQ1NNRSBUR0wgU1ZOMDEgS2VybmVsIERFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEtfPOoxER7WKkOQQFPnDBikHOrIkNZA1si7sFV1Y1tSBF4HCCl0BfXo5GqsOxzwJ2JcJLiP16ZP3rMcOOpufVLwPwN/0jmP1/KDeANgmwGLLvjAuHfx/KRU3MqkDdSLbfo4IBCDCCAQQwHwYDVR0jBBgwFoAUsd+j/J4YMaOrY0I0x9dKYND8mMQwHQYDVR0OBBYEFM8a2g/3TMuWX9hYlChnLZz1sJN9MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKsMIGgBgNVHR8EgZgwgZUwgZKgSqBIhkZodHRwczovL3RzREUuaW50ZWwuY29tL2NvbnRlbnQvT25EaWVDQS9jcmxzL09uRGllX0NBX0NTTUVfSW5kaXJlY3QuY3JsokSkQjBAMSYwJAYDVQQLDB1PbkRpZSBDQSBDU01FIEludGVybWVkaWF0ZSBDQTEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTAKBggqhkjOPQQDAwNoADBlAjB0WjT9RuE7v+dm2EM2uf7uZ3Pv3KAKZzBkpvokIbuO1qE3FS36mf3kKfl58hMhfosCMQD4NyxKd28cm9ZfW7eOEetEwXXDgCtq+rfzCXbJWDQvkYpnS4LPxIXxEsiN6/scTH0wggLAMIICRqADAgECAhBAAAAAAAAAAAAAAAAAAAAAMAoGCCqGSM49BAMDMEgxLjAsBgNVBAsMJU9uIERpZSBDU01FIERfVEdMIERFQlVHMDAwIElzc3VpbmcgQ0ExFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wHhcNMTkwMTAxMDAwMDAwWhcNNDkxMjMxMjM1OTU5WjAaMRgwFgYDVQQDDA9DU01FIFRHTCBST00gREUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ4g65/2ziA9osYJXOdQ81/PobyJmcTqSU8CMcVk3OyWhGjaczREvl+DvZpd5+2CYAxSr3ItlK5Jn3z1xG4mwHRzH0FFdu7Ooxf7kSH5dXnSO7hv6q/y97+KTy6odfzRuqjggEhMIIBHTAfBgNVHSMEGDAWgBQ7McrVw0uS10jI/ZKqda6dMkoGQjAdBgNVHQ4EFgQUsd+j/J4YMaOrY0I0x9dKYND8mMQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAa4wYgYIKwYBBQUHAQEEVjBUMFIGCCsGAQUFBzAChkZodHRwczovL3RzREUuaW50ZWwuY29tL2NvbnRlbnQvT25EaWVDQS9jZXJ0cy9UR0xfREVCVUcwMDBfT25EaWVfQ0EuY2VyMFYGA1UdHwRPME0wS6BJoEeGRWh0dHBzOi8vdHNERS5pbnRlbC5jb20vY29udGVudC9PbkRpZUNBL2NybHMvVEdMX0RFQlVHMDAwX09uRGllX0NBLmNybDAKBggqhkjOPQQDAwNoADBlAjAjX8BHXjQGsr1uqkCDdqRRzT2yQNLU4i85H+mJboRaAB2h09mISKagGU0m3DXywmICMQDmTjjpPjCJye9m2u/csfkUAn7rP1FLmdJHtT9qN968CACWQQ356e8s3XgNpNtexJU=","ReturnValue":0,"ReturnValueStr":"SUCCESS"}}'); // Sample Response 1
                        //response = JSON.parse('{"Header":{"To":"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous","RelatesTo":"15","Action":"http://intel.com/wbem/wscim/1/amt-schema/1/AMT_GeneralSettings/AMTAuthenticateResponse","MessageID":"uuid:00000000-8086-8086-8086-0000000000F8","ResourceURI":"http://intel.com/wbem/wscim/1/amt-schema/1/AMT_GeneralSettings","Method":"AMTAuthenticate"},"Body":{"Nonce":"NlfyHfo322EtefP1q5s92K+szBw=","UUID":"465A544C39335830B0304A51465A544C","FQDN":"","FWVersion":"15.0.10.7000","AMTSVN":1,"Signature":"9jBx0HfvNECPrMrg16px2RGDu/qdgrUyguOamlJ5hpiYgt9ZPrMz6/WgYY5nbnT6zBxSTUP+AqEzcmA6oWunYHZQJprY9iDdew4PPIHWqGZGgqh/10m3aYHwy+TKk/Ab","LengthOfCertificates":[603,638,631,708],"Certificates":"MIICVzCCAd2gAwIBAgIQSsxzEcw7W5elVuRWfkbN1zAKBggqhkjOPQQDAzAeMRwwGgYDVQQDDBNDU01FIFRHTCBBTVQgIDAxU0RFMB4XDTIwMDcyMzAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowFTETMBEGA1UEAwwKQU1UIFdTLU1BTjB2MBAGByqGSM49AgEGBSuBBAAiA2IABOiUImnj9foD828QWknCF47SuIhwKn+AzhcgPz7IaUb/Z9KTPn57VfxahHBObijKRodtcxao0Jip/0sM3wbXkHvF03BLdxP6/ab5uMYLH+ZDjdlwC69qkjQtXciIzml8u6OB6DCB5TAfBgNVHSMEGDAWgBS4jxQZFu/qvArLmfxFoa+HO3ZPhjAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEB/wQEAwIGgDCBoAYDVR0fBIGYMIGVMIGSoEqgSIZGaHR0cHM6Ly90c0RFLmludGVsLmNvbS9jb250ZW50L09uRGllQ0EvY3Jscy9PbkRpZV9DQV9DU01FX0luZGlyZWN0LmNybKJEpEIwQDEmMCQGA1UECwwdT25EaWUgQ0EgQ1NNRSBJbnRlcm1lZGlhdGUgQ0ExFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wCgYIKoZIzj0EAwMDaAAwZQIwYCfw7GuUi9XxfBfhO/LYUbSb3pd65tkpRSLjIhsj9uMG9DFbMVUy9aicvZt7NYwXAjEAtAdHvcmoI/fZfw2Mo7TooojLe+xfHzZ5NyZyVlPaVyya25K/3kE05gvQO1jvk/ZcMIICejCCAgGgAwIBAgIFAQQcACAwCgYIKoZIzj0EAwMwIzEhMB8GA1UEAwwYQ1NNRSBUR0wgU1ZOMDEgS2VybmVsIERFMB4XDTIwMDcyMzAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowHjEcMBoGA1UEAwwTQ1NNRSBUR0wgQU1UICAwMVNERTB2MBAGByqGSM49AgEGBSuBBAAiA2IABEv1wYCvKw5Q8nFMwqHCNU6663EMw9jpKtgSYX6koOjCsUTMnovdNxMJfeMpfrRbFqC7j4mQ1RP238SYIU8p7hsZN/GCPEJ/C95jy/moYd7UsVsQt5HbM61PXYDmyxftiKOCAQgwggEEMB8GA1UdIwQYMBaAFM8a2g/3TMuWX9hYlChnLZz1sJN9MB0GA1UdDgQWBBS4jxQZFu/qvArLmfxFoa+HO3ZPhjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDCBoAYDVR0fBIGYMIGVMIGSoEqgSIZGaHR0cHM6Ly90c0RFLmludGVsLmNvbS9jb250ZW50L09uRGllQ0EvY3Jscy9PbkRpZV9DQV9DU01FX0luZGlyZWN0LmNybKJEpEIwQDEmMCQGA1UECwwdT25EaWUgQ0EgQ1NNRSBJbnRlcm1lZGlhdGUgQ0ExFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wCgYIKoZIzj0EAwMDZwAwZAIwYlOLB2pq50pL5MKU21SWod9AkhsnFUsJVAlJ18RQRXApl0Hrl3RJSYl4WcjuQkH/AjAcZ0IIaCpZlAiocxGB4wzHVwCiXCGqc+pLEQ7mMnMTpRKcgY3oubVOTateqg3bdJ4wggJzMIIB+aADAgECAgEBMAoGCCqGSM49BAMDMBoxGDAWBgNVBAMMD0NTTUUgVEdMIFJPTSBERTAeFw0yMDA3MjMwMDAwMDBaFw00OTEyMzEyMzU5NTlaMCMxITAfBgNVBAMMGENTTUUgVEdMIFNWTjAxIEtlcm5lbCBERTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLXzzqMREe1ipDkEBT5wwYpBzqyJDWQNbIu7BVdWNbUgReBwgpdAX16ORqrDsc8CdiXCS4j9emT96zHDjqbn1S8D8Df9I5j9fyg3gDYJsBiy74wLh38fykVNzKpA3Ui236OCAQgwggEEMB8GA1UdIwQYMBaAFLHfo/yeGDGjq2NCNMfXSmDQ/JjEMB0GA1UdDgQWBBTPGtoP90zLll/YWJQoZy2c9bCTfTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICrDCBoAYDVR0fBIGYMIGVMIGSoEqgSIZGaHR0cHM6Ly90c0RFLmludGVsLmNvbS9jb250ZW50L09uRGllQ0EvY3Jscy9PbkRpZV9DQV9DU01FX0luZGlyZWN0LmNybKJEpEIwQDEmMCQGA1UECwwdT25EaWUgQ0EgQ1NNRSBJbnRlcm1lZGlhdGUgQ0ExFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wCgYIKoZIzj0EAwMDaAAwZQIwdFo0/UbhO7/nZthDNrn+7mdz79ygCmcwZKb6JCG7jtahNxUt+pn95Cn5efITIX6LAjEA+DcsSndvHJvWX1u3jhHrRMF1w4Aravq38wl2yVg0L5GKZ0uCz8SF8RLIjev7HEx9MIICwDCCAkagAwIBAgIQQAAAAAAAAAAAAAAAAAAAADAKBggqhkjOPQQDAzBIMS4wLAYDVQQLDCVPbiBEaWUgQ1NNRSBEX1RHTCBERUJVRzAwMCBJc3N1aW5nIENBMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMB4XDTE5MDEwMTAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowGjEYMBYGA1UEAwwPQ1NNRSBUR0wgUk9NIERFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEOIOuf9s4gPaLGCVznUPNfz6G8iZnE6klPAjHFZNzsloRo2nM0RL5fg72aXeftgmAMUq9yLZSuSZ989cRuJsB0cx9BRXbuzqMX+5Eh+XV50ju4b+qv8ve/ik8uqHX80bqo4IBITCCAR0wHwYDVR0jBBgwFoAUOzHK1cNLktdIyP2SqnWunTJKBkIwHQYDVR0OBBYEFLHfo/yeGDGjq2NCNMfXSmDQ/JjEMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGuMGIGCCsGAQUFBwEBBFYwVDBSBggrBgEFBQcwAoZGaHR0cHM6Ly90c0RFLmludGVsLmNvbS9jb250ZW50L09uRGllQ0EvY2VydHMvVEdMX0RFQlVHMDAwX09uRGllX0NBLmNlcjBWBgNVHR8ETzBNMEugSaBHhkVodHRwczovL3RzREUuaW50ZWwuY29tL2NvbnRlbnQvT25EaWVDQS9jcmxzL1RHTF9ERUJVRzAwMF9PbkRpZV9DQS5jcmwwCgYIKoZIzj0EAwMDaAAwZQIwI1/AR140BrK9bqpAg3akUc09skDS1OIvOR/piW6EWgAdodPZiEimoBlNJtw18sJiAjEA5k446T4wicnvZtrv3LH5FAJ+6z9RS5nSR7U/ajfevAgAlkEN+envLN14DaTbXsSV","ReturnValue":0,"ReturnValueStr":"SUCCESS"}}'); // Sample Response 2

                        if (status == 200) {
                            stack.amtauth = response.Body;
                            stack.amtauth.CertificatesDer = [];
                            var certs = [], urlList = [], certsbin = atob(stack.amtauth.Certificates), cptr = 0;
                            for (var i = 0; i < stack.amtauth.LengthOfCertificates.length; i++) {
                                var bin = certsbin.substring(cptr, cptr + stack.amtauth.LengthOfCertificates[i]);
                                stack.amtauth.CertificatesDer.push(bin);
                                var cert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(bin)); // Node-forge does not support ECC, but we are using a modified Node-forge that can still parse the cert.
                                cert.xCrlUrls = getExtensionUrls(cert, 'cRLDistributionPoints');
                                cert.xParentUrls = getExtensionUrls(cert, { id: '1.3.6.1.5.5.7.1.1' });
                                cert.xFingerprint = forge.md.sha256.create().update(bin).digest().toHex().toUpperCase();
                                cptr += stack.amtauth.LengthOfCertificates[i];
                                certs.push(cert);
                                if ((cert.xCrlUrls.length > 0) && (urlList.indexOf(cert.xCrlUrls[0]) == -1)) { urlList.push(cert.xCrlUrls[0]); }
                            }

                            // If the top certificate has a parent URL, add it to the list of URL's to fetch.
                            if ((certs.length > 0) && (certs[certs.length - 1].xParentUrls.length > 0) && (urlList.indexOf(certs[certs.length - 1].xParentUrls[0]) == -1)) {
                                urlList.push(certs[certs.length - 1].xParentUrls[0]);
                            }

                            stack.amtauth.Certificates = certs;
                            stack.amtauth.ClientNonce = stack.amtauthnonce;
                            delete stack.amtauth.LengthOfCertificates;
                            stack.amtauth.uuidStr = guidToStr(stack.amtauth.UUID).toLowerCase();

                            var trustedCsmeRoots = [
                                '3BA13766B1889DCB1E2D55BACCC9EC087452F78783E2EBAFD918FF4ED6ACC840', // www.intel.com / OnDie CA DEBUG Root Cert Signing CA
                                'C001DF02B31A60A2B37130365956400A2AFCFD147E8552FD7EA3F17F2AB0D457', // www.intel.com / ODCA CA2 CSME Intermediate CA
                                '5E3EEE5748AC13E0B3D1227FCDC4751AA1402DDE8031D21F63CB4ECF43F02440'  // www.intel.com / OnDie CA CSME Intermediate CA
                            ];

                            // Load the entire certificate chain and CRL's
                            var urlLoad = function (url, data) {
                                if (data == null) return;
                                for (var j in certs) {
                                    if ((certs[j].xCrlUrls.length > 0) && (certs[j].xCrlUrls[0] == url)) { certs[j].xCrl = data; }
                                    if ((j == (certs.length - 1)) && (certs[j].xParentUrls.length > 0) && (certs[j].xParentUrls[0] == url)) {
                                        var xcert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(data)); // Node-forge does not support ECC, but we are using a modified Node-forge that can still parse the cert.
                                        xcert.xCrlUrls = getExtensionUrls(xcert, 'cRLDistributionPoints');
                                        xcert.xParentUrls = getExtensionUrls(xcert, { id: '1.3.6.1.5.5.7.1.1' });
                                        xcert.xFingerprint = forge.md.sha256.create().update(data).digest().toHex().toUpperCase();
                                        if (trustedCsmeRoots.indexOf(xcert.xFingerprint) >= 0) { xcert.xTrusted = true; }
                                        certs.push(xcert);
                                        stack.amtauth.CertificatesDer.push(data);
                                        if ((xcert.xCrlUrls.length > 0) && (urlList.indexOf(xcert.xCrlUrls[0]) == -1)) { getCertUrl(xcert.xCrlUrls[0], urlLoad); }
                                        if ((xcert.xParentUrls.length > 0) && (urlList.indexOf(xcert.xParentUrls[0]) == -1)) { urlList.push(xcert.xParentUrls[0]); getCertUrl(xcert.xParentUrls[0], urlLoad); }
                                        return;
                                    }
                                }
                            }
                            for (var i in urlList) { getCertUrl(urlList[i], urlLoad); }
                        } else {
                            console.log('AMTAuthenticate', status, response);
                        }
                        delete stack.amtauthnonce;
                    });
                }
                // ###END###{Mode-NodeWebkit}

                // ###BEGIN###{ComputerSelector}
                if (stack.wsman.comm.digestRealm && (currentcomputer['digestrealm'] != stack.wsman.comm.digestRealm)) {
                    currentcomputer['digestrealm'] = stack.wsman.comm.digestRealm;
                    // ###BEGIN###{ComputerSelector-Local}
                    saveComputers();
                    // ###END###{ComputerSelector-Local}
                    updateComputerDetails();
                }
                // ###END###{ComputerSelector}

                // ###BEGIN###{VersionWarning}
                QV('id_versionWarning', checkAmtVersion(v));
                // ###END###{VersionWarning}
                // ###BEGIN###{!Mode-Firmware}
                //if (amtversion > 10) { wsstack.comm.MaxActiveAjaxCount = 4; amtstack.MaxActiveEnumsCount = 1; console.log('HTTP Pipelining activated'); } // With Intel AMT 11 and higher, use HTTP pipelining.
                // ###END###{!Mode-Firmware}

                PullSystemStatus();
                updateSystemStatus();

                // Perform loads more WSMAN only if needed
                if ((urlvars['kvmonly'] != 1) && (fullscreenonly == false)) {
                    PullUserInfo();

                    // ###BEGIN###{Alarms}
                    if (amtversion >= 8) PullAlarms();
                    // ###END###{Alarms}
                }

                // ###BEGIN###{Mode-NodeWebkit}
                if (wsstack.comm.getPeerCertificate() != null) {
                    QV('tlsNotification1', wsstack.comm.xtlsCheck == 1);
                    QV('tlsNotification2', wsstack.comm.xtlsCheck == 2);
                    QV('tlsNotification3', wsstack.comm.xtlsCheck == 3);
                }
                if (currentcomputer['tlscerthash2']) delete currentcomputer['tlscerthash2'];
                if (currentcomputer['tlscert2']) delete currentcomputer['tlscert2'];
                // ###END###{Mode-NodeWebkit}

                // Connection callback
                if (connectFunc) { connectFunc(connectFuncTag); connectFunc = null; connectFuncTag = null; }

                // ###BEGIN###{Desktop}
                if (urlvars['kvm'] == 1) { go(14); connectDesktop(); }
                if ((urlvars['kvmfull'] == 1) || (urlvars['kvmonly'] == 1)) { go(14); connectDesktop(); }
                // ###END###{Desktop}
                // ###BEGIN###{Terminal}
                if (urlvars['sol'] == 1) { go(13); connectTerminal(); }
                // ###END###{Terminal}

                // ###BEGIN###{Scripting}
                // ###BEGIN###{Mode-NodeWebkit}
                // ###BEGIN###{!ComputerSelector-Local-ScriptOnly}
                if (urlvars['host'] && urlvars['script']) {
                    try {
                        var data = require('fs').readFileSync(urlvars['script'], 'utf8');
                        if (data) { script_onScriptRead( { target: { result: data }} ); }
                    } catch (e) { messagebox("Run Script", "Invalid script file.") }
                }
                // ###END###{!ComputerSelector-Local-ScriptOnly}
                // ###END###{Mode-NodeWebkit}
                // ###END###{Scripting}
            } else {
                errcheck(status, stack);
            }
        }

        // Control the state of all refresh buttons
        var refreshButtonsState = true;
        function refreshButtons(x) {
            if (refreshButtonsState == x) return;
            refreshButtonsState = x;
            var i = 0, e = document.getElementsByTagName('input');
            for (; i < e.length; i++) { if (e[i].name == 'refreshbtn') { e[i].disabled = !x; } }
        }

        // Store certificate pinning
        // ###BEGIN###{Mode-NodeWebkit}
        function storeCertPinning(host, hash) {
            var pins = {};
            try { pins = JSON.parse(localStorage.getItem('amtcertpins')); } catch (e) { }
            if ((pins == null) || (typeof pins != 'object')) { pins = {}; }
            if (hash) { pins[host] = hash; } else { delete pins[host]; }
            try { localStorage.setItem('amtcertpins', JSON.stringify(pins)); } catch (ex) { }
        }

        function getCertPinnings() { try { var x = JSON.parse(localStorage.getItem('amtcertpins')); if ((x == null) || (typeof x != 'object')) return {}; return x; } catch (e) { return {} } }
        function getCertPinning(host) { return getCertPinnings()[host]; }

        // ###END###{Mode-NodeWebkit}

        // Display TLS certificate
        // ###BEGIN###{Mode-NodeWebkit}
        var showTlsCertTempCert;
        function showTlsCert(buttons, msg, cert, tag, func) {
            if (xxdialogMode) return;
            var c = showTlsCertTempCert = cert?cert:wsstack.comm.getPeerCertificate(), x = '<br>';
            if (msg) x = '<div>' + msg + '</div><br />';
            // ###BEGIN###{FileSaver}
            x += addHtmlValue("Certificate", c.raw.length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=downloadTlsCert()>' + "Download" + '</a>');
            // ###END###{FileSaver}
            // ###BEGIN###{!FileSaver}
            x += addHtmlValue("Certificate", c.raw.length + " bytes");
            // ###END###{!FileSaver}

            // Display certificate key usages
            var y = [];
            if (c.ext_key_usage.indexOf('1.3.6.1.5.5.7.3.2') >= 0) { y.push(NoBreak("TLS Client")); }
            if (c.ext_key_usage.indexOf('1.3.6.1.5.5.7.3.3') >= 0) { y.push(NoBreak("Code Signing")); }
            if (c.ext_key_usage.indexOf('1.3.6.1.5.5.7.3.4') >= 0) { y.push("EMail"); }
            if (c.ext_key_usage.indexOf('1.3.6.1.5.5.7.3.1') >= 0) { y.push(NoBreak("TLS Server")); }
            if (c.ext_key_usage.indexOf('2.16.840.1.113741.1.2.1') >= 0) { y.push(NoBreak("Intel&reg; AMT Console")); }
            if (c.ext_key_usage.indexOf('2.16.840.1.113741.1.2.2') >= 0) { y.push(NoBreak("Intel&reg; AMT Agent")); }
            if (c.ext_key_usage.indexOf('2.16.840.1.113741.1.2.3') >= 0) { y.push(NoBreak("Intel&reg; AMT Activation")); }
            if (c.ext_key_usage.indexOf('1.3.6.1.5.5.7.3.8') >= 0) { y.push(NoBreak("Time Stamping")); }
            if (y.length > 0) { x += addHtmlValueNoTitle("Certificate Usage", y.join(', ') + '.') + '<br clear=all />'; }

            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Certificate Subject" + '</i></div><br>';
            for (var i in c.subject) { if (c.subject[i]) { x += addHtmlValue(xxCertSubjectNames[i] ? xxCertSubjectNames[i] : i, EscapeHtml(MakeToArray(c.subject[i]).join(', '))); } }
            x += addHtmlValueNoTitle("Fingerprint", c.fingerprint.substring(0,29) + '<br />' + c.fingerprint.substring(30));
            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Issuer Certificate" + '</i></div><br>';
            for (var i in c.issuer) { if (c.issuer[i]) { x += addHtmlValue(xxCertSubjectNames[i] ? xxCertSubjectNames[i] : i, EscapeHtml(MakeToArray(c.issuer[i]).join(', '))); } }
            if (func == null) { func = showTlsCertDefault; }
            setDialogMode(11, "TLS Certificate - " + EscapeHtml(c.subject['CN']), buttons, func, x, { c: c, m: tag });
        }

        function showTlsCertDefault(b, args) {
            var cert = args.c, mode = args.m;
            if (b == 0) { disconnect(); }
            if (b == 1) {
                currentcomputer['tlscerthash'] = cert.fingerprint.split(':').join('').toLowerCase();
                currentcomputer['tlscert'] = cert.raw.toString('hex');
                currentcomputer['tlscerthash2'] = cert.fingerprint.split(':').join('').toLowerCase();
                currentcomputer['tlscert2'] = cert.raw.toString('hex');
                storeCertPinning(currentcomputer.host, cert.fingerprint.split(':').join('').toLowerCase());
                // ###BEGIN###{ComputerSelector-Local}
                saveComputers();
                // ###END###{ComputerSelector-Local}
                updateComputerDetails();
                if (mode == 1) {
                    // Reconnect immidiatly
                    computerConnect(undefined, currentcomputer['h'], 0, true);
                }
            }
        }

        function downloadTlsCert() {
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('nwsaveas', showTlsCertTempCert.subject['CN'] + '.cer');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, showTlsCertTempCert.raw, 'binary', function () { }); }, false);
            chooser.click();
        }

        function switchToTls() {
            if (xxTlsCurrentCert == null) {
                setDialogMode(11, "Switch to TLS", 3, switchToTls1, "The connection is currently not secured. Click OK to setup Intel AMT with TLS and switch to a secure connection.");
            } else {
                setDialogMode(11, "Switch to TLS", 3, switchToTls1, "The connection is currently not secured and Intel AMT is already setup with TLS. Click OK to switch to a secure connection.");
            }
        }

        function switchToTls1() {
            // Check if Intel AMT is already setup with TLS.
            if (xxTlsCurrentCert == null) {
                // TLS is not setup, start by asking Intel AMT to generate a key pair
                messagebox("TLS Setup", "Generating certificate key...");
                amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, switchToTls2);
            } else {
                // Setup the certificate pinning and reconnect
                var cert = null;
                try { cert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(xxCertificates[xxTlsCurrentCert].X509Certificate)); } catch (ex) { messagebox("TLS Certificate", "Failed to read TLS certificate: " + ex); return; }
                currentcomputer['tlscert'] = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).toHex();
                currentcomputer['tlscerthash'] = forge.md.sha1.create().update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()).digest().toHex();
                currentcomputer['tls'] = 1;
                updateComputerDetails();
                saveComputers();

                // Disconnect and reconnect immidiatly
                disconnect();
                computerConnect(undefined, currentcomputer['h'], 0, true);
            }
        }

        function switchToTls2(stack, serviceName, response, status) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }
            if (response.Body['ReturnValue'] != 0) { messagebox("Issue Certificate", "Failed to generate key pair, " + response.Body['ReturnValueStr']); return; }

            // Get the new key pair
            messagebox("TLS Setup", "Fetching certificate key...");
            amtstack.Enum('AMT_PublicPrivateKeyPair', switchToTls3, response.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
        }

        function switchToTls3(stack, serviceName, response, status, tag) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }
            var DERKey = null;
            for (var i in response) { if (response[i]['InstanceID'] == tag) DERKey = response[i]['DERKey']; }

            // Sign the key pair using the CA certifiate
            messagebox("TLS Setup", "Creating TLS certificate...");

            var name = ''
            try { name = amtsysstate['AMT_GeneralSettings'].response['HostName']; } catch (ex) { }
            if ((name == null) || (name == '')) { name = currentcomputer['name']; }
            if ((name == null) || (name == '')) { name = currentcomputer['host']; }
            var cert = amtcert_signWithCaKey(DERKey, null, { 'CN': name, 'O': "None", 'ST': "None", 'C': "None" }, { 'CN': "Untrusted Root Certificate" }, { name: 'extKeyUsage', serverAuth: true });
            if (cert == null) { messagebox("Issue Certificate", "Unable to sign certificate."); return; }

            // Save cert and cert hash in computer list
            messagebox("TLS Setup", "Uploading TLS certificate...");
            currentcomputer['tlscert'] = forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).toHex();
            currentcomputer['tlscerthash'] = forge.md.sha1.create().update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()).digest().toHex();
            updateComputerDetails();
            saveComputers();

            // Place the resulting signed certificate back into AMT
            var pem = forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
            amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), switchToTls4);
        }

        function switchToTls4(stack, serviceName, response, status) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }

            messagebox("TLS Setup", "Setting TLS certificate...");
            var certInstanceId = response.Body['CreatedCertificate']['ReferenceParameters']['SelectorSet']['Selector']['Value'];

            // Set the TLS certificate
            setTlsSecurityPendingCalls = 3;
            if (xxTLSCredentialContext.length > 0) {
                // Modify the current context
                var newTLSCredentialContext = Clone(xxTLSCredentialContext[0]);
                newTLSCredentialContext['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'] = certInstanceId;
                amtstack.Put('AMT_TLSCredentialContext', newTLSCredentialContext, switchToTls5, 0, 1);
            } else {
                // Add a new security context
                amtstack.Create('AMT_TLSCredentialContext', {
                    'ElementInContext': '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + certInstanceId + '</w:Selector></w:SelectorSet></a:ReferenceParameters>',
                    'ElementProvidingContext': '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_TLSProtocolEndpointCollection') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="ElementName">TLSProtocolEndpointInstances Collection</w:Selector></w:SelectorSet></a:ReferenceParameters>'
                }, switchToTls5);
            }

            // Figure out what index is local & remote
            var localNdx = ((xxTlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);

            // Remote TLS settings
            var xxTlsSettings2 = Clone(xxTlsSettings);
            xxTlsSettings2[remoteNdx]['Enabled'] = true;
            xxTlsSettings2[remoteNdx]['MutualAuthentication'] = false;
            xxTlsSettings2[remoteNdx]['AcceptNonSecureConnections'] = true;
            delete xxTlsSettings2[remoteNdx]['TrustedCN'];

            // Local TLS settings
            xxTlsSettings2[localNdx]['Enabled'] = true;
            delete xxTlsSettings2[localNdx]['TrustedCN'];

            // Update TLS settings
            amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], switchToTls5, 0, 1, xxTlsSettings2[0]);
            amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], switchToTls5, 0, 1, xxTlsSettings2[1]);
        }

        function switchToTls5(stack, name, response, status) {
            if (stack) {
                if (status != 200) { messagebox('', "Failed to set TLS certificate, status = " + status); return; }
                if (response.Body['ReturnValueStr'] && !methodcheck(response)) return;
            }

            // Check if all the calls are done & perform a commit
            if ((--setTlsSecurityPendingCalls) == 0) {
                messagebox("TLS Setup", "Performing commit...");
                amtstack.AMT_SetupAndConfigurationService_CommitChanges(null, switchToTls6);
            }
        }

        function switchToTls6(stack, name, response, status) {
            if (status != 200) { messagebox('', "Failed to set TLS security, status = " + status); return; }
            if (response.Body['ReturnValue'] != 0) { messagebox('', "Failed to set TLS security, error: " + response.Body['ReturnValueStr']); return; }

            // Switch current computer to TLS
            messagebox("TLS Setup", "TLS setup completed.");
            currentcomputer['tls'] = 1;
            updateComputerDetails();
            saveComputers();

            setTimeout(function () {
                setDialogMode();

                // Disconnect and reconnect immidiatly
                disconnect();
                computerConnect(undefined, currentcomputer['h'], 0, true);
            }, 2000);
        }

        // ###END###{Mode-NodeWebkit}

        //
        // SYSTEM STATUS PANEL
        //

        // ###BEGIN###{PowerControl}
        function PullPowerState() {
            if (amtstack && amtstack.GetPendingActions() == 0 && amtsysstate && amtsysstate['CIM_ServiceAvailableToElement']) {
                amtstack.Enum('CIM_ServiceAvailableToElement', function (stack, name, responses, status) {
                    if (status != 200) return; // If the polling fails, just skip it.
                    amtsysstate['CIM_ServiceAvailableToElement'].responses = responses;
                    if ((amtversion > 9) && (amtsysstate['CIM_ServiceAvailableToElement'] != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses.length > 0) && (amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'] == 2)) {
                        // If Intel AMT 10+ and powered on, poll the OS power state.
                        amtstack.Get('IPS_PowerManagementService', function (stack, name, response, status) {
                            if (status == 200) { amtsysstate['IPS_PowerManagementService'].response = response.Body; updateSystemStatus(); }
                        });
                    } else {
                        updateSystemStatus();
                    }
                });

            }
        }
        // ###END###{PowerControl}

        function PullSystemStatus(x) {
            refreshButtons(false);
            amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(processSystemTime);
            // ###BEGIN###{Look-Intel-SBT}
            amtstack.BatchEnum('', ['*AMT_GeneralSettings'], processSystemStatus);
            // ###END###{Look-Intel-SBT}
            // ###BEGIN###{!Look-Intel-SBT}
            var query = ['CIM_ServiceAvailableToElement', '*AMT_GeneralSettings', 'AMT_EthernetPortSettings', '*AMT_RedirectionService', 'CIM_ElementSettingData', '*AMT_BootCapabilities'];
            if (amtversion > 5) query.push('IPS_IPv6PortSettings', '*CIM_KVMRedirectionSAP', '*IPS_OptInService','*IPS_KVMRedirectionSettingData');
            if (amtversion > 9) query.push('*IPS_ScreenConfigurationService', '*IPS_PowerManagementService');
            if (amtversion > 15) query.push('*CIM_BootService');
            // ###BEGIN###{NetAuth}
            if (amtversion > 2) query.push('*AMT_8021XProfile');
            // ###END###{NetAuth}
            amtstack.BatchEnum('', query, processSystemStatus, true);
            // ###END###{!Look-Intel-SBT}
            // ###BEGIN###{Wireless}
            if (x == 1) PullWireless();
            // ###END###{Wireless}
        }

        function processSystemTime(stack, name, responses, status) {
            if (errcheck(status, stack)) return;
            if (status == 200) {
                // Convert ms to time and adjust for the timezone
                var t = new Date(), t2 = new Date();
                //t.setTime(responses.Body['Ta0'] * 1000 + (t.getTimezoneOffset() * 60 * 1000));
                t.setTime(responses.Body['Ta0'] * 1000);
                amtdeltatime = t - t2;
                updateSystemStatus();
            }
        }

        var amtdeltatime;
        var amtsysstate;
        var amtlogicalelements; // processSystemVersion
        var amtfeatures = {};
        function processSystemStatus(stack, name, responses, status) {
            // ###BEGIN###{ComputerSelector}
            if (wsstack == null || amtstack != stack) return;
            // ###END###{ComputerSelector}
            // If this computer has no KVM, ignore and continue (Standard Manageability)
            if ((responses['IPS_ScreenConfigurationService'] == undefined) || (responses['IPS_ScreenConfigurationService'].status == 400)) { responses['IPS_ScreenConfigurationService'] = null; }
            if ((responses['IPS_KVMRedirectionSettingData'] == undefined) || (responses['IPS_KVMRedirectionSettingData'].status == 400)) { responses['IPS_KVMRedirectionSettingData'] = null; }
            if ((responses['CIM_KVMRedirectionSAP'] == undefined) || (responses['CIM_KVMRedirectionSAP'].status == 400)) { responses['CIM_KVMRedirectionSAP'] = null; }
            if ((responses['IPS_OptInService'] == undefined) || (responses['IPS_OptInService'].status == 400)) { responses['IPS_OptInService'] = null; }
            if ((responses['AMT_RedirectionService'] != undefined) && (responses['AMT_RedirectionService'].status == 200)) { QV('go13', true); } // Show the terminal
            
            // Reset the status after possible KVM removal
            status = 0;
            for (var i in responses) { if ((responses[i] != null) && (responses[i].status > status)) { status = responses[i].status; } }

            if ((status != 400) && errcheck(status, stack)) return;
            amtsysstate = responses;
            applyDesktopSettings();
            updateSystemStatus();
        }

        // Ask to synchronize the Intel AMT clock
        function syncClock() {
            if (xxdialogMode) return;
            setDialogMode(11, "Synchronize Clock", 3, syncClockEx, "Synchronize Intel AMT clock with this computer?");
        }

        // Synchronize the Intel AMT clock
        function syncClockEx() {
            amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(function (stack, name, response, status) {
                if (status != 200) { messagebox('', "Failed to set time, status = " + status); return; }
                if (response.Body['ReturnValue'] != 0) { messagebox('', "Failed to set time, error: " + response.Body['ReturnValueStr']); return; }
                //var now = new Date(), Tm1 = Math.round((now.getTime() - (now.getTimezoneOffset() * 60000)) / 1000);
                var now = new Date(), Tm1 = Math.round(now.getTime() / 1000);
                amtstack.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch(response.Body['Ta0'], Tm1, Tm1, function () { amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(processSystemTime); });
            });
        }

        // ###BEGIN###{PowerControl}
        var DMTFPowerStates = ['', '', "Power on", "Light sleep", "Deep sleep", "Power cycle (Soft off)", "Off - Hard", "Hibernate (Off soft)", "Soft off", "Power cycle (Off-hard)", "Main bus reset", "Diagnostic interrupt (NMI)", "Not applicable", "Off - Soft graceful", "Off - Hard graceful", "Master bus reset graceful", "Power cycle (Off - Soft graceful)", "Power cycle (Off - Hard graceful)", "Diagnostic interrupt (INIT)"];
        // ###END###{PowerControl}
        function updateSystemStatus() {
            if ((!amtsysstate) || (currentView > 99)) return;

            // System Status Table
            var systemdefense = 0, host, y, x = TableStart(), features = '', gs = amtsysstate['AMT_GeneralSettings'].response;
            // ###BEGIN###{PowerControl}
            var t = '<i>' + "Unknown" + '</i>';
            if ((amtsysstate['CIM_ServiceAvailableToElement'] != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses.length > 0)) {
                t = DMTFPowerStates[amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState']];
                // If Intel AMT 10+, check OS power saving state.
                if ((amtversion > 9) && (t == "Power on") && (amtsysstate['IPS_PowerManagementService']) && (amtsysstate['IPS_PowerManagementService'].response) && (amtsysstate['IPS_PowerManagementService'].response['OSPowerSavingState'] == 3)) { t = 'Standby (Connected)'; }
                // ###BEGIN###{Terminal}
                QH('id_p13power', t); // Display the power state on the terminal form
                // ###END###{Terminal}
                // ###BEGIN###{Desktop}
                //if ((desktop.State != 0) && (Q('id_p14power').innerHTML.length > 0) && (Q('id_p14power').innerHTML != t)) { desktop.Stop(); setTimeout(connectDesktop, 150); }
                QH('id_p14power', t); // Display the power state on the desktop form
                // ###END###{Desktop}
            }
            if (gs['PowerSource']) t += [", Plugged-in", ", On Battery"][gs['PowerSource']];
            x += TableEntry("Power", addLink(t, 'showPowerActionDlg()'));
            // ###END###{PowerControl}

            host = gs['HostName'];
            y = gs['DomainName'];
            if (y != null && y.length > 0) host += '.' + y;
            if (host.length == 0) { host = ('<i>' + "None" + '</i>'); } else { host = EscapeHtml(host); }
            x += TableEntry("Name & Domain", addLinkConditional(host, 'showEditNameDlg()', xxAccountAdminName));
            if (amtstack.amtauth && amtstack.amtauth.uuidStr) {
                x += TableEntry("System ID", amtstack.amtauth.uuidStr);
            } else if (HardwareInventory) {
                x += TableEntry("System ID", guidToStr(HardwareInventory['CIM_ComputerSystemPackage'].response['PlatformGUID'].toLowerCase()));
            }
            if (amtlogicalelements) {
                var mode = '', scs = getItem(amtlogicalelements, 'CreationClassName', 'AMT_SetupAndConfigurationService');
                // ###BEGIN###{!Look-Intel-SBT}
                if ((scs['ProvisioningState'] == 2) && (amtversion > 5)) {
                    mode = " activated in Admin Control Mode (ACM)";
                    if (scs['ProvisioningMode'] == 4) { mode = " activated in Client Control Mode (CCM)"; systemdefense = 9; }
                }
                // ###END###{!Look-Intel-SBT}

                // ###BEGIN###{Look-Intel-SBT}
                x += TableEntry("Intel&reg; SBT", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-Intel-SBT}
                // ###BEGIN###{Look-Intel-SM}
                x += TableEntry("Intel&reg; SM", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-Intel-SM}
                // ###BEGIN###{Look-Intel-AMT}
                x += TableEntry("Intel&reg; AMT", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-Intel-AMT}
                // ###BEGIN###{Look-Commander}
                x += TableEntry("Intel&reg; ME", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-Commander}
                // ###BEGIN###{Look-ISDU}
                x += TableEntry("Intel&reg; ME", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-ISDU}
                // ###BEGIN###{Look-BrandedCommander}
                x += TableEntry("Intel&reg; ME", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-BrandedCommander}
                // ###BEGIN###{Look-Unite}
                x += TableEntry("Intel&reg; ME", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-Unite}
                // ###BEGIN###{Look-MeshCentral}
                x += TableEntry("Intel&reg; ME", 'v' + getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'] + mode);
                // ###END###{Look-MeshCentral}

                // ###BEGIN###{ComputerSelector}
                currentcomputer['ver'] = getItem(amtlogicalelements, 'InstanceID', 'AMT')['VersionString'];
                currentcomputer['pstate'] = scs['ProvisioningState'];
                currentcomputer['pmode'] = scs['ProvisioningMode'];
                currentcomputer['date'] = new Date().toISOString();
                updateComputerDetails();
                // ###BEGIN###{ComputerSelector-Local}
                saveComputers();
                // ###END###{ComputerSelector-Local}
                // ###END###{ComputerSelector}
            }

            // ###BEGIN###{!Mode-MeshCentral2}

            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                QH('id_computername', "Computer: " + ((gs['HostName'] == '') ? ('<i>' + "None" + '</i>') : gs['HostName']) + ", Server: " + meshCentralServer.host);
            } else {
                QH('id_computername', "Computer: " + ((gs['HostName'] == '') ? ('<i>' + "None" + '</i>') : gs['HostName']));
            }
            // ###END###{MeshServerConnect}
            // ###BEGIN###{!MeshServerConnect}
            QH('id_computername', "Computer: " + ((gs['HostName'] == '') ? ('<i>' + "None" + '</i>') : gs['HostName']));
            // ###END###{!MeshServerConnect}

            // ###END###{!Mode-MeshCentral2}
            // ###BEGIN###{Mode-NodeWebkit}
            if (gs['HostName'] != '') { require('nw.gui').Window.get().title = NW_WindowTitle + ' - ' + gs['HostName']; } else { require('nw.gui').Window.get().title = NW_WindowTitle; }
            // ###END###{Mode-NodeWebkit}

            // ###BEGIN###{PowerControl}
            if ((amtsysstate['CIM_ServiceAvailableToElement'] != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses.length > 0)) {
                // Intel AMT power state warning. If computer is not powered on, display a warning in terminal and desktop panels.
                // ###BEGIN###{Terminal}
                QV('id_p13warning2', amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'] != 2);
                // ###END###{Terminal}
                // ###BEGIN###{Desktop}
                QV('id_p14warning2', amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'] != 2);
                // ###END###{Desktop}
            }
            // ###END###{PowerControl}

            // ###BEGIN###{!Look-Intel-SBT}
            // Intel AMT Features
            if (amtsysstate['AMT_RedirectionService'].status == 200) {
                var redir = amtfeatures[0] = (amtsysstate['AMT_RedirectionService'].response['ListenerEnabled'] == true);
                var sol = amtfeatures[1] = ((amtsysstate['AMT_RedirectionService'].response['EnabledState'] & 2) != 0);
                var ider = amtfeatures[2] = ((amtsysstate['AMT_RedirectionService'].response['EnabledState'] & 1) != 0);
                var kvm = amtfeatures[3] = undefined;
                if ((amtversion > 5) && (amtsysstate['CIM_KVMRedirectionSAP'] != null)) {
                    // ###BEGIN###{Desktop}
                    QV('go14', true); // Desktop
                    // ###END###{Desktop}
                    kvm = amtfeatures[3] = ((amtsysstate['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6 && amtsysstate['CIM_KVMRedirectionSAP'].response['RequestedState'] == 2) || amtsysstate['CIM_KVMRedirectionSAP'].response['EnabledState'] == 2 || amtsysstate['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6);
                }
                if (redir) features += ", Redirection Port";
                if (sol) features += ", Serial-over-LAN";
                if (ider) features += ", IDE-Redirect";
                if (kvm) features += ", KVM";
                if (features == '') features = '  ' + "None";
                x += TableEntry("Active Features", addLinkConditional(features.substring(2), 'showFeaturesDlg()', xxAccountAdminName));
            }

            if ((amtsysstate['IPS_KVMRedirectionSettingData'] != null) && (amtsysstate['IPS_KVMRedirectionSettingData'].response)) {
                var desktopSettings = amtsysstate['IPS_KVMRedirectionSettingData'].response;
                var screenname = "Primary display";
                if ((amtversion > 7) && (desktopSettings['DefaultScreen'] !== undefined) && (desktopSettings['DefaultScreen'] < 255)) { screenname = ["Primary display", "Secondary display", "3rd display"][desktopSettings['DefaultScreen']]; }
                features = '<span title="' + format("The default remote display is {0}", screenname.toLowerCase()) + '">' + screenname + '</span>';
                if (desktopSettings['Is5900PortEnabled'] == true) { features += ", Port 5900 enabled"; }
                if (desktopSettings['OptInPolicy'] == true) { features += ", " + desktopSettings['OptInPolicyTimeout'] + ' ' + ((desktopSettings['OptInPolicyTimeout'] > 0)?"seconds opt-in":"second opt-in"); }
                features += ", " + desktopSettings['SessionTimeout'] + " minute" + ((desktopSettings['SessionTimeout'] > 0) ? 's' : '') + " session timeout";

                // Screen blanking on AMT 10 and higher
                if ((amtversion > 9) && (amtsysstate['IPS_ScreenConfigurationService'] != null)) {
                    var screenBlanking = ((amtsysstate['IPS_ScreenConfigurationService'].response['EnabledState'] & 1) != 0);
                    if (screenBlanking) features += ", Blanking Allowed";
                    // ###BEGIN###{Desktop}
                    QV('id_DeskSBspan', screenBlanking);
                    Q('id_DeskSB').checked = false;
                    // ###END###{Desktop}
                } else {
                    // ###BEGIN###{Desktop}
                    QV('id_DeskSBspan', false);
                    // ###END###{Desktop}
                }

                // ###BEGIN###{Desktop-Settings}
                x += TableEntry("Remote Desktop", addLinkConditional(features, 'showDesktopSettingsDlg()', xxAccountAdminName));
                // ###END###{Desktop-Settings}
                // ###BEGIN###{!Desktop-Settings}
                x += TableEntry("Remote Desktop", features);
                // ###END###{!Desktop-Settings}
            }
            // ###BEGIN###{Terminal}
            QV('id_p13warning1', !redir || !sol); // Show the warning box on top of the terminal if redirection or sol is disabled.
            QV('id_p13warninga', xxAccountAdminName); // If we are not administrator, we can't activate SOL.
            // ###END###{Terminal}
            // ###BEGIN###{Desktop}
            QV('id_p14warning1', !redir || !kvm); // Show the warning box on top of the remote desktop viewer if redirection or kvm is disabled.
            QV('id_p14warninga', xxAccountAdminName); // If we are not administrator, we can't activate KVM.
            // ###END###{Desktop}

            // Intel AMT user Consent
            if ((amtversion > 5) && (amtsysstate != null && amtsysstate['IPS_OptInService'] != null) && (amtsysstate['IPS_OptInService'].response != undefined)) {
                features = "Unknown state";
                var optinrequired = amtsysstate['IPS_OptInService'].response['OptInRequired'];
                if (optinrequired == 0) { features = "Not Required"; }
                if (optinrequired == 1) { features = "Required for KVM only"; }
                if (optinrequired == 0xFFFFFFFF) { features = "Always Required"; }
                if (amtsysstate['IPS_OptInService'].response['CanModifyOptInPolicy'] == true) features = addLinkConditional(features, 'showConsentDlg()', xxAccountAdminName); // If we can modify user consent settings, add the link to do it.
                x += TableEntry("User Consent", features);
            }

            // Power Options
            if ((amtsysstate['AMT_BootCapabilities'].response['PlatformErase'] != null) && (amtsysstate['AMT_BootCapabilities'].response['PlatformErase'] > 0) && (amtsysstate['CIM_BootService'] != null) && (amtsysstate['CIM_BootService'].response['EnabledState'] != null)) {
                var enabledBootStateStr = { 0: "Unknown", 1: "Other", 2: "Enabled", 3: "Disabled", 4: "Shutting Down", 5: "Not Applicable", 6: "Enabled but Offline", 7: "In Test", 8: "Deferred", 9: "Quiesce", 10: "Starting", 32768: "OCR Disabled", 32769: "OCR Enabled", 32770: "OCR Disabled, RPE Enabled", 32771: "RPE & OCR Enabled" };
                if (amtversion > 15) { enabledBootStateStr[32768] = "OCR & RPE Disabled"; enabledBootStateStr[32769] = "OCR Enabled, RPE Disabled"; }
                var t = enabledBootStateStr[amtsysstate['CIM_BootService'].response['EnabledState']]?enabledBootStateStr[amtsysstate['CIM_BootService'].response['EnabledState']]:"Unknown";
                x += TableEntry("Boot Features", addLinkConditional(t, 'showEnableBootServiceDlg()', xxAccountAdminName));
            }

            // Intel AMT Power policy
            if (AmtSystemPowerSchemes != null) {
                var elementSettings = amtsysstate['CIM_ElementSettingData'].responses;
                for (var i = 0; i < elementSettings.length; i++) {
                    if (elementSettings[i]['SettingData'] && elementSettings[i]['IsCurrent'] == 1 && elementSettings[i]['SettingData']['ReferenceParameters']['ResourceURI'] == 'http://intel.com/wbem/wscim/1/amt-schema/1/AMT_SystemPowerScheme') {
                        // Found the active Intel AMT power scheme
                        var powerguid = elementSettings[i]['SettingData']['ReferenceParameters']['SelectorSet']['Selector'][1]['Value'];
                        // Now find the name of the power schema in the AMT_SystemPowerScheme table
                        for (var j = 0; j < AmtSystemPowerSchemes.length; j++) {
                            if (AmtSystemPowerSchemes[j]['SchemeGUID'] == powerguid) {
                                // Found the power scheme name
                                x += TableEntry("Power Policy", addLinkConditional(AmtSystemPowerSchemes[j]['Description'].split(':' )[1], 'showPowerPolicyDlg(\"' + powerguid + '\")', xxAccountAdminName));
                            }
                        }
                    }
                }
            }
            // ###END###{!Look-Intel-SBT}

            if (amtdeltatime) { x += TableEntry("Date & Time", addLinkConditional(new Date(new Date().getTime() + amtdeltatime).toLocaleString(), 'syncClock()', xxAccountAdminName)); }
            var buttons = AddRefreshButton('PullSystemStatus()') + ' ';
            // ###BEGIN###{PowerControl}
            buttons += AddButton("Power Actions...", 'showPowerActionDlg()') + ' ';
            // ###END###{PowerControl}
            // ###BEGIN###{WsmanBrowser}
            // ###BEGIN###{FileSaver}
            buttons += AddButton("Save State...", 'saveEntireAmtState()') + ' ';
            // ###END###{FileSaver}
            // ###END###{WsmanBrowser}
            // ###BEGIN###{Scripting}
            buttons += AddButton("Run Script...", 'script_runScriptDlg()') + ' ';
            // ###END###{Scripting}
            x += TableEnd(buttons);

            // Show authentic CSME if present
            if (amtstack.amtauth) { x += '<div style=position:absolute;top:10px;right:20px;cursor:pointer onclick=showAuthCsme()><img src=authcsme.png width=100 height=100 /></div>'; }

            QH('id_TableSysStatus', x);

            // ###BEGIN###{NetworkSettings}
            var x = '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px>';
            x += TableEnd('<div>&nbsp;' + AddRefreshButton('PullSystemStatus(1)')
                // ###BEGIN###{!Mode-LMS}
                + " Changing network settings may cause this page to become unavailable."
                // ###END###{!Mode-LMS}
                // ###BEGIN###{Mode-LMS}
                + " Changing network settings may cause this page to be unavailable for a few seconds."
                // ###END###{Mode-LMS}
            );

            // General settings
            x += '<br><h2>' + "General Settings" + '</h2>';
            x += TableStart();

            // Network state
            // if (gs['AMTNetworkEnabled']) { x += TableEntry("Network state", (gs['AMTNetworkEnabled']==1)?"Enabled":"Disabled"); }

            // Shared FQDN
            var fqdnshare = '';
            if (host != '<i>' + "None" + '</i>') {
                if (gs['SharedFQDN'] == true) fqdnshare = ", shared with OS";
                if (gs['SharedFQDN'] == false) fqdnshare = ", different from OS";
            }
            x += TableEntry("Name & Domain", addLinkConditional(host + fqdnshare, 'showEditNameDlg(1)', xxAccountAdminName));

            // Dynamic DNS
            var ddns = "Disabled";
            if (gs['DDNSUpdateEnabled'] == true) {
                ddns = "Enabled each " + gs['DDNSPeriodicUpdateInterval'] + " minutes, TTL is " + gs['DDNSTTL'] + " minutes";
            } else if (gs['DDNSUpdateByDHCPServerEnabled'] == true) {
                ddns = "Update by DHCP server";
            }
            x += TableEntry("Dynamic DNS", addLinkConditional(ddns, 'showEditDnsDlg()', xxAccountAdminName));
            x += TableEnd();

            for (var y in amtsysstate['AMT_EthernetPortSettings'].responses) {
                var z = amtsysstate['AMT_EthernetPortSettings'].responses[y];
                if (z['WLANLinkProtectionLevel'] || (y == 1)) { amtwirelessif = y; } // Set the wireless interface, this seems to cover new wireless only computers and older computers with dual interfaces.
                if ((y == 0) && (amtwirelessif != y) && (z['MACAddress'] == '00-00-00-00-00-00')) { continue; } // On computers with only wireless, the wired interface will have a null MAC, skip it.
                if (y == 0) systemdefense++;
                x += '<br><h2>' + ((amtwirelessif == y)?"Wireless Interface":"Wired Interface") + '</h2>';
                x += TableStart();

                /*
                var lp = [], linkpolicy = MakeToArray(z['LinkPolicy']);
                for (var p in linkpolicy) {
                    var ap = linkpolicy[p];
                    if (ap == 1) lp.push("S0/AC");
                    if (ap == 14) lp.push("Sx/AC");
                    if (ap == 16) lp.push("S0/DC");
                    if (ap == 224) lp.push("Sx/DC");
                }
                x += TableEntry("Link state", (z['LinkIsUp'] == true?"Link is up":"Link is down") + ", available in " + lp.join(', '));
                */
                x += TableEntry("Link state", (z['LinkIsUp'] == true?"Link is up":"Link is down"));
                if (z['LinkPolicy']) {
                    z['LinkPolicy'] = MakeToArray(z['LinkPolicy']);
                    var linkPolicyStr = [];
                    for (var i in z['LinkPolicy']) {
                        if (z['LinkPolicy'][i] == 1) { linkPolicyStr.push("S0/AC"); }
                        if (z['LinkPolicy'][i] == 14) { linkPolicyStr.push("Sx/AC"); }
                        if (z['LinkPolicy'][i] == 16) { linkPolicyStr.push("S0/DC"); }
                        if (z['LinkPolicy'][i] == 224) { linkPolicyStr.push("Sx/DC"); }
                    }
                    if (linkPolicyStr.length == 0) { linkPolicyStr.push(''); }
                    x += TableEntry("Link policy", addLinkConditional((linkPolicyStr.length == 0) ? "Not available" : "Available in: " + linkPolicyStr.join(', '), 'showLinkPolicyDlg(' + y + ')', xxAccountAdminName));
                }
                if (z['MACAddress'] != '00-00-00-00-00-00') { x += TableEntry("MAC address", z['MACAddress']); }

                // ###BEGIN###{Wireless}
                if ((amtwirelessif == y) && xxWireless && xxWireless['CIM_WiFiPortCapabilities'].response) {
                    // Start and state
                    x += TableEntry("State", addLinkConditional(xxWifiState[xxWireless['CIM_WiFiPort'].response['EnabledState']], 'showWifiStateDlg()', xxAccountAdminName));
        
                    /* This is not that useful
                    // Capabilities
                    var s = '', sc = xxWireless['CIM_WiFiPortCapabilities'].response, supportedTypes = sc['SupportedPortTypes'];
                    for (i in supportedTypes) { s += ", 802.11" + "abgn"[supportedTypes[i] - 70]; }
                    x += TableEntry("Capabilites", s.substring(2));
                    */

                    // Current radio state
                    s = xxWireless['CIM_WiFiEndpoint'].response['LANID'];
                    x += TableEntry("Radio State", xxRadioState[xxWireless['CIM_WiFiEndpoint'].response['EnabledState']] + ", SSID: " + (s ? s : ('<i>' + "None" + '</i>')));

                    // Current local profile synchronization
                    if (xxWireless['AMT_WiFiPortConfigurationService'] && xxWireless['AMT_WiFiPortConfigurationService'].response && (typeof xxWireless['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 'number')) {
                        x += TableEntry("Local WIFI Profile Sync", addLinkConditional(((xxWireless['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 1) ? "Enabled" : "Disabled"), 'showWifiSyncDlg(' + y + ')', xxAccountAdminName));
                    }
                    // CSME UEFI Wifi profile sharing, check if it is enabled in boot setting and it is not null at AMT_WiFiPortConfigrationService
                    if (amtsysstate['AMT_BootCapabilities'].response['UEFIWiFiCoExistenceAndProfileShare'] != null && amtsysstate['AMT_BootCapabilities'].response['UEFIWiFiCoExistenceAndProfileShare'] == true
                        && xxWireless['AMT_WiFiPortConfigurationService'].response['UEFIWiFiProfileShareEnabled']!=null) {
                            x += TableEntry("UEFI WiFi CoEx Profile sharing", addLinkConditional(xxWireless['AMT_WiFiPortConfigurationService'].response['UEFIWiFiProfileShareEnabled']==1? "Enabled":"Disabled", 'showUefiWifiCoExDlg()', xxAccountAdminName));
                     } else {
                        x += TableEntry("UEFI WiFi CoEx Profile sharing", "Unavailable");
                     }
                }
                // ###END###{Wireless}

                if (amtwirelessif != y) {
                    // Things that are specific to the wired interface
                    x += TableEntry("Respond to ping", addLinkConditional(["Disabled", "ICMP response", "RMCP response", "ICMP & RMCP response"][gs['PingResponseEnabled'] + (gs['RmcpPingResponseEnabled'] << 1)], 'showPingActionDlg()', xxAccountAdminName));
                    // ###BEGIN###{NetAuth}
                    // 802.1x
                    var netAuthProtocols = ['EAP-TLS', 'EAP-TTLS/MSCHAPv2', 'PEAPv0/EAP-MSCHAPv2', 'PEAPv1/EAP-GTC', 'EAP-FAST/MSCHAPv2', 'EAP-FAST/GTC', 'EAP-FAST/TLS'], netAuthStr = "Disabled";
                    if (amtsysstate['AMT_8021XProfile'].responses.Body['Enabled']) { netAuthStr = "Enabled, " + netAuthProtocols[amtsysstate['AMT_8021XProfile'].responses.Body['AuthenticationProtocol']]; }
                    x += TableEntry("802.1x", addLinkConditional(netAuthStr, 'editNetAuthProfile()', xxAccountAdminName));
                    // ###END###{NetAuth}
                    var ipStateString = z['DHCPEnabled'] == true ? "Automatic using DHCP server" : "Static IP address";
                    if (z['IpSyncEnabled'] == true) { ipStateString += ', IP sync with OS'; }
                    x += TableEntry("IPv4 state", addLinkConditional(ipStateString, 'showIPSetupDlg()', xxAccountAdminName));
                }

                // Display IPv4 current settings
                x += TableEntry("IPv4 address", isIpAddress(z['IPAddress'],"None"));
                if (isIpAddress(z['DefaultGateway'])) { x += TableEntry("IPv4 gateway / Mask", z['DefaultGateway'] + ' / ' + isIpAddress(z['SubnetMask'],"None")); }
                
                var dns = z['PrimaryDNS'];
                if (isIpAddress(dns)) {
                    if (z['SecondaryDNS']) dns += ' / ' + z['SecondaryDNS'];
                    x += TableEntry("IPv4 domain name server", dns);
                }

                if ((amtsysstate['IPS_IPv6PortSettings'].status == 200) && (amtversion > 5)) {
                    // Check if IPv6 is enabled for this interface
                    var zz = amtsysstate['IPS_IPv6PortSettings'].responses[y];
                    var ipv6state = "Disabled", ipv6, ipv6manual, elementSettings = amtsysstate['CIM_ElementSettingData'].responses;
                    for (var i = 0; i < elementSettings.length; i++) {
                        if (elementSettings[i]['SettingData'] && elementSettings[i]['SettingData']['ReferenceParameters']['SelectorSet']['Selector']['Value'] == 'Intel(r) IPS IPv6 Settings ' + y) {
                            ipv6 = (elementSettings[i]['IsCurrent'] == 1);
                        }
                    }

                    // Check if manual addresses have been added
                    if (ipv6 == true) { 
                        ipv6manual = isIpAddress(zz['IPv6Address']) || isIpAddress(zz['DefaultRouter']) || isIpAddress(zz['PrimaryDNS']) || isIpAddress(zz['SecondaryDNS']);
                        ipv6state = (ipv6manual ? "Enabled, Automatic & manual addresses" : "Enabled, Automatic addresses");
                    }

                    // Display IPv6 current settings
                    x += TableEntry("IPv6 state", addLinkConditional(ipv6state, 'showIPv6StateDlg(' + y + ',' + ipv6 + ')', xxAccountAdminName));
                    if (ipv6 == true) {
                        if (zz['CurrentAddressInfo'] && zz['CurrentAddressInfo'].length > 0) {
                            zz['CurrentAddressInfo'] = MakeToArray(zz['CurrentAddressInfo']); // Because our WSMAN stack does not know if this is a array, we need to make it an array if it contains 1 element.
                            ipv6addr = '';
                            for (var i = 0; i < zz['CurrentAddressInfo'].length; i++) { if (ipv6addr.length > 0) ipv6addr += ", "; ipv6addr += zz['CurrentAddressInfo'][i].split(',')[0]; }
                            x += TableEntry("IPv6 address", addLink(ipv6addr, 'showIPv6AddrDlg(' + y + ',\"' + zz['CurrentAddressInfo'] + '\")'));
                        } else {
                            x += TableEntry("IPv6 address", "None");
                        }
                        if (isIpAddress(zz['CurrentDefaultRouter'])) { x += TableEntry("IPv6 default router", zz['CurrentDefaultRouter']); }
                        if (isIpAddress(zz['CurrentPrimaryDNS'])) {
                            var dns = zz['CurrentPrimaryDNS'];
                            if (isIpAddress(zz['CurrentSecondaryDNS'])) dns += ' / ' + zz['CurrentSecondaryDNS'];
                            x += TableEntry("IPv6 domain name server", dns);
                        }
                    }
                }

                x += TableEnd();
            }

            // Only do more WSMAN if we need it
            if ((urlvars['kvmonly'] != 1) && (fullscreenonly == false)) {
                // ###BEGIN###{Wireless}
                // If there is a wireless interface, get the data for it. If not, show that there is not.
                if (amtwirelessif != -1) { if ((amtFirstPull & 2) == 0) PullWireless(); }
                // ###END###{Wireless}
                QH('id_TableNetworkSettingsSpan', x);
                // ###END###{NetworkSettings}

                // ###BEGIN###{SystemDefense}
                // If in ACM mode and we have a wired interface, pull System Defense information
                if ((systemdefense == 1) && ((amtFirstPull & 4) == 0)) PullSystemDefense();
                // ###END###{SystemDefense}

                // ###BEGIN###{Storage}
                if (((amtFirstPull & 8) == 0) && (amtversion > 11 || ((amtversion == 11) && (amtversionmin > 5)))) { PullStorage(); }
                // ###END###{Storage}
            }

            if (currentView == 0) go(1, 1); // If we are at the loading screen, most to System Status screen
        }

        function isIpAddress(t, x) { return (t && t != null && t.length > 0 && t != '::' && t != '::0')?t:x; }

        function showLinkPolicyDlg(y) {
            if (xxdialogMode) return;
            var z = amtsysstate['AMT_EthernetPortSettings'].responses[y], s = '';
            s += '<label><input type=checkbox id=d11p1 value=1 ' + ((z['LinkPolicy'].indexOf(1) >= 0) ? 'checked' : '') + '>Available in S0/AC - Powered on & plugged in</label><br>';
            s += '<label><input type=checkbox id=d11p2 value=14 ' + ((z['LinkPolicy'].indexOf(14) >= 0) ? 'checked' : '') + '>Available in Sx/AC - Sleeping & plugged in</label><br>';
            s += '<label><input type=checkbox id=d11p3 value=16 ' + ((z['LinkPolicy'].indexOf(16) >= 0) ? 'checked' : '') + '>Available in S0/DC - Powered on & on battery</label><br>';
            s += '<label><input type=checkbox id=d11p4 value=224 ' + ((z['LinkPolicy'].indexOf(224) >= 0) ? 'checked' : '') + '>Available in Sx/DC - Sleeping & on battery</label><br>';
            setDialogMode(11, "Link Policy", 3, showLinkPolicyDlgEx, s, y);
        }

        function showLinkPolicyDlgEx(b, y) {
            var x = Clone(amtsysstate['AMT_EthernetPortSettings'].responses[y]);
            if (x['DHCPEnabled']) {
                delete x['IPAddress'];
                delete x['SubnetMask'];
                delete x['DefaultGateway'];
                delete x['PrimaryDNS'];
                delete x['SecondaryDNS'];
            }
            x['LinkPolicy'] = [];
            if (Q('d11p1').checked) { x['LinkPolicy'].push(1); }
            if (Q('d11p2').checked) { x['LinkPolicy'].push(14); }
            if (Q('d11p3').checked) { x['LinkPolicy'].push(16); }
            if (Q('d11p4').checked) { x['LinkPolicy'].push(224); }
            amtstack.Put('AMT_EthernetPortSettings', x, showLinkPolicyDlgExDone, 0, 1, x);
        }

        function showLinkPolicyDlgExDone(stack, name, response, status) {
            if (status == 200) {
                amtsysstate = undefined;
                PullSystemStatus();
            } else {
                messagebox("Link Policy", format("Unable to set new link policy, error {0}", status));
            }
        }

        function showAuthCsme() {
            if (xxdialogMode) return;
            var x = '<div style=margin-top:8px>' + "Intel&reg; AMT supports authentic CSME feature, however MeshCommander cannot verify the authenticity yet." + '</div><hr style=margin-top:8px;margin-bottom:8px;height:2px;border-width:0;color:gray;background-color:gray />';
            x += addHtmlValue("FW Version", amtstack.amtauth.FWVersion);
            x += addHtmlValue("FQDN", amtstack.amtauth.FQDN ? amtstack.amtauth.FQDN : ('<i>' + "None" + '</i>'));
            x += '<hr style=margin-top:8px;margin-bottom:8px;height:2px;border-width:0;color:gray;background-color:gray /><div style=max-height:200px;overflow-y:auto><table>';
            for (var i in amtstack.amtauth.Certificates) {
                var cert = amtstack.amtauth.Certificates[i];
                x += '<tr><td style=width:32px;vertical-align:top><img src=images-commander/cert1.png height=32 width=32 />';
                x += '<td style=padding-bottom:6px><b>' + EscapeHtml(cert.subject.getField('CN').value) + ((cert.xTrusted === true) ? ', <span style=color:#080>' + "Trusted" + '</span>' : '') + '</b><br />';
                if (cert.subject.getField('OU')) { x += EscapeHtml(cert.subject.getField('OU').value) + '<br />'; }
                // ###BEGIN###{FileSaver}
                x += amtstack.amtauth.CertificatesDer[i].length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=downloadAuthCert(' + i + ')>' + "Download" + '</a>';
                if (cert.xCrl) { x += '<br />' + "CRL " + cert.xCrl.length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=downloadCertCrl(' + i + ')>' + "Download" + '</a>'; }
                // ###END###{FileSaver}
                // ###BEGIN###{!FileSaver}
                x += amtstack.amtauth.CertificatesDer[i].length + " bytes";
                if (cert.xCrl) { x += '<br />' + "CRL " + cert.xCrl.length + " bytes"; }
                // ###END###{!FileSaver}
            }
            x += '</table><div>';
            setDialogMode(11, "Authentic CSME", 1, null, x);
        }

        // ###BEGIN###{FileSaver}
        function downloadCertCrl(h) {
            h = parseInt(h);
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(amtstack.amtauth.Certificates[h].xCrl), amtstack.amtauth.Certificates[h].subject.getField('CN').value + '.crl');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('nwsaveas', amtstack.amtauth.Certificates[h].subject.getField('CN').value + '.crl');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, amtstack.amtauth.Certificates[h].xCrl, 'binary', function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }

        function downloadAuthCert(h) {
            h = parseInt(h);
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(amtstack.amtauth.CertificatesDer[h]), amtstack.amtauth.Certificates[h].subject.getField('CN').value + '.cer');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('nwsaveas', amtstack.amtauth.Certificates[h].subject.getField('CN').value + '.cer');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, amtstack.amtauth.CertificatesDer[h], 'binary', function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

// ###BEGIN###{WsmanBrowser}
// ###BEGIN###{FileSaver}
        var IntelAmtEntireState;
        var IntelAmtEntireStateCalls;
        function saveEntireAmtState() {
            if (xxdialogMode) return;
            var n = '', d = new Date();
            if (amtsysstate) { n = '-' + amtsysstate['AMT_GeneralSettings'].response['HostName']; }
            n += '-' + d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);;
            idx_d19savestatefilename.value = 'amtstate' + n + '.json';
            setDialogMode(19, "Save Entire Intel&reg; AMT State", 3, saveEntireAmtStateOk);
        }

        function saveEntireAmtStateOk() {
            IntelAmtEntireState = { 'webappversion':version,'localtime':Date(),'utctime':new Date().toUTCString(),'isotime':new Date().toISOString() };
            QH('id_dialogMessage', 'Fetching entire state, please wait...');
            setDialogMode(1, "Save Entire Intel&reg; AMT State", 0, null);

            // Fetch everything!
            IntelAmtEntireStateCalls = 3;
            amtstack.BatchEnum(null, AllWsman, saveEntireAmtStateOk2, null, true);
            amtstack.GetAuditLog(saveEntireAmtStateOk3);
            amtstack.GetMessageLog(saveEntireAmtStateOk4);
        }

        function saveEntireAmtStateOk2(stack, name, responses, status) { IntelAmtEntireState['wsmanenums'] = responses; saveEntireAmtStateDone(); }
        function saveEntireAmtStateOk3(stack, messages) { IntelAmtEntireState['auditlog'] = messages; saveEntireAmtStateDone(); }
        function saveEntireAmtStateOk4(stack, messages) { IntelAmtEntireState['eventlog'] = messages; saveEntireAmtStateDone(); }

        function saveEntireAmtStateDone() {
            if (--IntelAmtEntireStateCalls != 0) return;
            setDialogMode();
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(JSON.stringify(IntelAmtEntireState, null, '  ').replace(/\n/g, '\r\n')), idx_d19savestatefilename.value);
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('nwsaveas', idx_d19savestatefilename.value);
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, JSON.stringify(IntelAmtEntireState, null, '  ').replace(/\n/g, '\r\n'), function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
// ###END###{FileSaver}
// ###END###{WsmanBrowser}

// ###BEGIN###{Desktop-Settings}

        function showDesktopSettingsDlg() {
            if (xxdialogMode) return;
            var desktopSettings = amtsysstate['IPS_KVMRedirectionSettingData'].response;
            var x = '<div style=text-align:left>';
            x += '<div style=height:26px;margin-top:4px><select id=subddisplay style=float:right;width:200px><option value=0>' + "Primary display" + '</option><option value=1>' + "Secondary display" + '</option>';
            if (amtversion > 9) { x += '<option value=2>' + "3rd display" + '</option>'; }
            x += '</select><div style=padding-top:4px>' + "Default display" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=subsessiontimeout style=float:right;width:200px maxlength=5 onkeypress="return numbersOnly(event)"><div style=padding-top:4px>' + "Session timeout (Minutes)" + '</div></div>';
            if (desktopSettings['OptInPolicy'] == true) { x += '<div style=height:26px;margin-top:4px><input id=suboptintimeout style=float:right;width:200px maxlength=5 onkeypress="return numbersOnly(event)"><div style=padding-top:4px>' + "Opt-in timeout (Seconds)" + '</div></div>'; }
            x += '<div style=height:26px;margin-top:4px><select id=subdlegacy style=float:right;width:200px onchange=showDesktopSettingsDlgUpdate()><option value=0>' + "Disabled, Recommended" + '</option><option value=1>' + "Enabled, Legacy KVM viewers" + '</option></select><div style=padding-top:4px>' + "Port 5900" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px id=subspassx><input id=subspass type=password autocomplete=off style=float:right;width:200px maxlength=8 onkeyup=showDesktopSettingsDlgUpdate()><div style=padding-top:4px>' + "5900 password (8 chars)" + '</div></div>';
            if ((amtversion > 9) && (amtsysstate['IPS_ScreenConfigurationService'] != null)) { x += '<div style=height:26px;margin-top:4px><select id=subsb style=float:right;width:200px onchange=showDesktopSettingsDlgUpdate()><option value=0>' + "Disabled" + '</option><option value=1>' + "Enabled" + '</option></select><div style=padding-top:4px title="' + "This feature is not often supported" + '">' + "Screen Blanking" + '</div></div>'; }
            x += '</div>';
            setDialogMode(11, "Remote Desktop Settings", 3, showDesktopSettingsDlgOk, x);
            Q('subddisplay').value = desktopSettings['DefaultScreen'];
            Q('subsessiontimeout').value = desktopSettings['SessionTimeout'];
            if (desktopSettings['OptInPolicy'] == true) { Q('suboptintimeout').value = desktopSettings['OptInPolicyTimeout']; }
            Q('subdlegacy').value = ((desktopSettings['Is5900PortEnabled'] == true) ? 1 : 0);
            if ((amtversion > 9) && (amtsysstate['IPS_ScreenConfigurationService'] != null)) { Q('subsb').value = amtsysstate['IPS_ScreenConfigurationService'].response['EnabledState']; }
            showDesktopSettingsDlgUpdate();
        }

        function showDesktopSettingsDlgUpdate() {
            QV('subspassx', (Q('subdlegacy').value == 1));
            var ok = ((Q('subdlegacy').value == 0) || (Q('subspass').value.length == 8) || (Q('subspass').value.length == 0)) && (Q('subsessiontimeout').value.length > 0);
            if ((amtsysstate['IPS_KVMRedirectionSettingData'].response['OptInPolicy'] == true) && (Q('suboptintimeout').value.length == 0)) { ok = false; }
            QE('idx_dlgOkButton', ok);
        }

        function showDesktopSettingsDlgOk() {
            var x = Clone(amtsysstate['IPS_KVMRedirectionSettingData'].response);
            x['DefaultScreen'] = Q('subddisplay').value
            x['SessionTimeout'] = Q('subsessiontimeout').value;
            x['Is5900PortEnabled'] = (Q('subdlegacy').value == 1);
            if (x['OptInPolicy'] == true) { x['OptInPolicyTimeout'] = Q('suboptintimeout').value; }
            if (x['Is5900PortEnabled'] == true) { x['RFBPassword'] = Q('subspass').value; }
            amtstack.Put('IPS_KVMRedirectionSettingData', x, showDesktopSettingsDlgOk2);

            // Screen blanking
            var y = Clone(amtsysstate['IPS_ScreenConfigurationService'].response);
            y['EnabledState'] = parseInt(Q('subsb').value);
            amtstack.Put('IPS_ScreenConfigurationService', y, showDesktopSettingsDlgOk3);
        }

        function showDesktopSettingsDlgOk2(stack, name, responses, status) {
            if (status == 200) PullSystemStatus(); else messagebox("Remote Desktop Settings", format("Error {0}, unable to set values.", status));
        }

        function showDesktopSettingsDlgOk3(stack, name, response, status) {
            if (status != 200) { messagebox("Error", format("Screen Blanking could not be set, blanking may not be supported on this system ({0}).", status)); return; }
            amtstack.Get('IPS_ScreenConfigurationService', function (stack, name, response, status) {
                if (status == 200) { amtsysstate['IPS_ScreenConfigurationService'].response = response.Body; updateSystemStatus(); }
            }, 0, 1);
        }

// ###END###{Desktop-Settings}

// ###BEGIN###{EventLog}

        //
        // EVENT LOG PANEL
        //

        function PullEventLog(button) {
            if (button == 1 && xxdialogMode) return;
            amtFirstPull |= 16;
            amtstack.Enum('AMT_MessageLog', processMessageLog0);
            amtstack.GetMessageLog(processMessageLog1);
        }

        var processMessageLog0responses = null;
        function processMessageLog0(stack, name, responses, status) {
            if (status != 200) return;
            if (status) QV('go6', true); // Show event log left panel option
            if (responses) processMessageLog0responses = responses;
            var fr = '', x = '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px>';
            if (processMessageLog0responses != null) { fr = ((processMessageLog0responses[0]['IsFrozen'] == true) ? AddButton("Un-freeze Log", 'FreezeLog(0)') : AddButton("Freeze Log", 'FreezeLog(1)')); }

            // ###BEGIN###{!FileSaver}
            x += TableEnd('<div style=float:right><input id=eventFilter placeholder="' + "Filter" + '" style=margin:4px onkeyup=eventFilter()>&nbsp;</div><div>&nbsp;' + AddRefreshButton('PullEventLog(1)') + AddButton("Clear Log", 'ClearLog()') + fr);
            // ###END###{!FileSaver}
            // ###BEGIN###{FileSaver}
            x += TableEnd('<div style=float:right><input id=eventFilter placeholder="' + "Filter" + '" style=margin:4px onkeyup=eventFilter()>&nbsp;</div><div>&nbsp;' + AddRefreshButton('PullEventLog(1)') + AddButton("Clear Log", 'ClearLog()') + AddButton("Save...", 'SaveEventLog()') + fr);
            // ###END###{FileSaver}
            QH('id_TableEventLog', x + '<br>');
        }

        // ###BEGIN###{FileSaver}
        function SaveEventLog() {
            if (xxdialogMode || eventmessages == null) return;
            SaveJsonFile('IntelAmtEventlog', 'events', 'Intel AMT Event Log', eventmessages);
        }
        // ###END###{FileSaver}

        var eventmessages = null;
        function processMessageLog1(stack, messages) {
            eventmessages = messages;
            var i, y = 0, x = '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=80px><p><td><td><td>';
            x += '<tr><td class=r1 style=width:90px><b>&nbsp;&nbsp;Event</b><td class=r1 style=width:110px><b>Time</b><td class=r1 style=width:160px><b>' + "Source" + '</b><td class=r1><b>' + "Description" + '</b>';
            for (i in messages) {
                y++;
                var icon = 1, m = messages[i];
                if (m['EventSeverity'] >= 8) { icon = 2; } if (m['EventSeverity'] >= 16) { icon = 3; }
                x += '<tr id=xamtevent' + i + ' class=r3 onclick=showEventDetails(' + i + ')><td class=r1><p><div class=icon' + icon + ' style=display:block;float:left;margin-left:5px;margin-right:5px></div>' + (parseInt(i) + 1) + '<td class=r1 title="' + m['Time'].toLocaleString() + '">' + m['Time'].toLocaleDateString('en', { year: 'numeric', month: '2-digit', day: 'numeric' }) + '<br>' + m['Time'].toLocaleTimeString('en', { hour:'2-digit', minute:'2-digit', second:'2-digit' }) + '<td class=r1>' + m['EntityStr'].replace('(r)', '&reg;') + '<td class=r1>' + m['Desc'];
            }
            x += TableEnd(y == 0 ? '&nbsp;' : '');
            QH('id_TableEventLog2', x + '<br>');
            processMessageLog0();
        }

        function FreezeLog(x) { if (!xxdialogMode) { amtstack.AMT_MessageLog_FreezeLog(x, function () { amtstack.Enum('AMT_MessageLog', processMessageLog0); }) } }
        function ClearLog(x) { if (!xxdialogMode) { QH('id_dialogMessage', "Clear event log?"); setDialogMode(1, "Event Log", 3, ClearLogEx); } }
        function ClearLogEx() { amtstack.AMT_MessageLog_ClearLog(function (stack, name, responses, status) { if (status != 200) messagebox("Event Log", "Unable to clear, Error: " + status); else PullEventLog(); }) }

        function showEventDetails(h) {
            if (xxdialogMode) return;
            var m = eventmessages[h];
            var x = '<div style=text-align:left>';
            x += addHtmlValue("Time", m['Time'].toLocaleString());
            x += addHtmlValue("Source", m['EntityStr'].replace('(r)', '&reg;'));
            x += addHtmlValue("Description", m['Desc']);
            x += MoreStart();
            x += addHtmlValue("Device Address", m['DeviceAddress']);
            x += addHtmlValue("Entity", m['Entity']);
            x += addHtmlValue("Entity Instance", m['EntityInstance']);
            var e = '';
            for (var i in m['EventData']) { if (e.length > 0) e +=','; e += m['EventData'][i]; }
            x += addHtmlValue("Data", e);
            x += addHtmlValue("Offset", m['EventOffset']);
            x += addHtmlValue("Sensor Type", m['EventSensorType']);
            x += addHtmlValue("Severity", m['EventSeverity']);
            x += addHtmlValue("Source Type", m['EventSourceType']);
            x += addHtmlValue("Type", m['EventType']);
            x += addHtmlValue("Sensor Number", m['SensorNumber']);
            x += MoreEnd();
            x += '</div>';
            messagebox(format("Event #{0} Details", h + 1), x);
        }

        function eventFilter() {
            var filter = Q('eventFilter').value.toLowerCase();
            for (var w in eventmessages) { QV('xamtevent' + w, filter == '' || eventmessages[w]['Desc'].toLowerCase().indexOf(filter) >= 0 || eventmessages[w]['EntityStr'].toLowerCase().indexOf(filter) >= 0); }
        }

// ###END###{EventLog}

// ###BEGIN###{EventSubscriptions}

        //
        // EVENT SUBSCRIPTION PANEL
        //

        var subscriptionsFilters = null; // List of event filters
        var subscriptionsListeners = null; // List of subscribers

        function PullEventSubscriptions() {
            if (subscriptionsFilters == null) { amtstack.Enum('CIM_FilterCollection', processEventSubscriptions0); }
            amtstack.BatchEnum(null, ['CIM_ListenerDestination', 'CIM_FilterCollectionSubscription'], processEventSubscriptions1);
        }

        function processEventSubscriptions0(stack, name, responses, status) {
            if (status == 408 || status == 400) return;
            if (status && errcheck(status, stack)) return;
            subscriptionsFilters = responses;
        }

        function processEventSubscriptions1(stack, name, responses, status) {
            if (status == 408 || status == 400) return;
            if (status && errcheck(status, stack)) return;
            if (status) QV('go22', true); // Show event subscription left panel option
            if (responses) subscriptionsListeners = responses;
            var c= 0, x = TableStart2() + '<tr><td class=r1 style=padding-left:15px><br>' + "Manage event subscribers." + '<br><br>';
            for (var i in subscriptionsListeners['CIM_ListenerDestination']['responses']) {
                var f = subscriptionsListeners['CIM_FilterCollectionSubscription']['responses'][i]['Filter']['ReferenceParameters']['SelectorSet']['Selector']['Value'].replace('(r)', '&reg;');
                var r = subscriptionsListeners['CIM_ListenerDestination']['responses'][i];
                x += '<div class=itemBar onclick="showSubscriptionDetails(' + i + ')"><div style=float:right></div><div style=padding-top:3px;overflow-x:hidden title="' + f + ' - ' + r['Destination'] + '"><b>' + f + '</b> - ' + r['Destination'] + '</div><div style=padding-top:3px></div></div>';
                c++;
            }
            if (c == 0) x += ('<div style=padding-left:15px><br><i>' + "No subscriptions found." + '</i></div><br>');
            var y = '<div>&nbsp;' + AddRefreshButton('PullEventSubscriptions()');
            if (xxAccountAdminName) y += AddButton("New Subscription", 'newSubscriptionButton()');
            x += '<br><td class=r1>' + TableEnd(y + '</div>');
            QH('id_TableEventSubscriptions', x);
        }

        var subscriptionDeliveryModes = { 2:"Push", 3:"Push with ACK", 4:"Events", 5:"Pull" };
        function showSubscriptionDetails(h) {
            if (xxdialogMode) return;
            var f = subscriptionsListeners['CIM_FilterCollectionSubscription']['responses'][h]['Filter']['ReferenceParameters']['SelectorSet']['Selector']['Value'].replace('(r)', '&reg;');
            var r = subscriptionsListeners['CIM_ListenerDestination']['responses'][h];
            var x = '<div style=text-align:left>';
            x += addHtmlValue("Destination", r['Destination']);
            x += addHtmlValue("Filter", f);
            x += addHtmlValue("Delivery Mode", subscriptionDeliveryModes[r['DeliveryMode']]);
            x += '</div>';
            setDialogMode(11, "Subscription " + (h + 1), xxAccountAdminName?5:1, deleteSubscriptionButton, x, h);
        }

        function deleteSubscriptionButton(button, h) {
            if (button != 2) return;
            var name = subscriptionsListeners['CIM_ListenerDestination']['responses'][h]['Name'];
            var filter = subscriptionsListeners['CIM_FilterCollectionSubscription']['responses'][h]['Filter']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
            amtstack.UnSubscribe('CIM_FilterCollectionSubscription', PullEventSubscriptions, null, 1, {'Filter':'<a:EndpointReference><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_FilterCollection</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + filter + '</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference>', 'Handler':'<a:EndpointReference><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ListenerDestinationWSManagement</w:ResourceURI><w:SelectorSet><w:Selector Name="CreationClassName">CIM_ListenerDestinationWSMAN</w:Selector><w:Selector Name="Name">' + name + '</w:Selector><w:Selector Name="SystemCreationClassName">CIM_ComputerSystem</w:Selector><w:Selector Name="SystemName">Intel(r) AMT</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference>'});
        }

        function newSubscriptionButton() {
            if (xxdialogMode || (subscriptionsFilters == null)) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><select id=subtype style=float:right;width:260px><option value=Push>' + "Push" + '</option><option value=PushWithAck>' + "Push with ACK" + '</option></select><div style=padding-top:4px>' + "Type" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=subfilter style=float:right;width:260px>';
            for (var i in subscriptionsFilters) { x += '<option value="' + subscriptionsFilters[i]['InstanceID'] + '">' + subscriptionsFilters[i]['CollectionName'].substring(13) + '</option>'; }
            x += '</select><div style=padding-top:4px>' + "Filter" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=suburl style=float:right;width:260px maxlength=253 onkeyup=newSubscriptionUpdate() value="http://"><div style=padding-top:4px>' + "URL" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=subauth style=float:right;width:260px onchange=newSubscriptionUpdate()><option value=0>' + "None" + '</option><option value=1>' + "Digest" + '</option></select><div style=padding-top:4px>' + "Authentication" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px id=subxuser><input id=subuser style=float:right;width:260px maxlength=32 onkeyup=newSubscriptionUpdate()><div style=padding-top:4px>' + "Username" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px id=subxpass><input id=subpass style=float:right;width:260px maxlength=32 onkeyup=newSubscriptionUpdate()><div style=padding-top:4px>' + "Password" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=subargs style=float:right;width:260px maxlength=128><div style=padding-top:4px>' + "Arguments" + '</div></div>';
            setDialogMode(11, "Add Event Subscription", 3, newSubscriptionButtonOk, x);
            newSubscriptionUpdate();
        }

        function newSubscriptionUpdate() {
            QE('idx_dlgOkButton', ((Q('suburl').value.length > 0) && (Q('suburl').value.startsWith('http://')) && ((Q('subauth').value == 0) || ((Q('subuser').value.length > 0) && (Q('subpass').value.length > 0)))));
            QV('subxuser', Q('subauth').value == 1);
            QV('subxpass', Q('subauth').value == 1);
        }

        function newSubscriptionButtonOk() {
            var user = (Q('subuser').value.length == 0)?undefined:Q('subuser').value, pass = (Q('subpass').value.length == 0)?undefined:Q('subpass').value;
            amtstack.Subscribe('CIM_FilterCollection', Q('subtype').value, Q('suburl').value, newSubscriptionButtonOk2, null, 1, { 'InstanceID' : Q('subfilter').value }, (Q('subargs').value.length > 0)?Q('subargs').value:null, user, pass);
        }

        function newSubscriptionButtonOk2(stack, name, responses, status) {
            if (status == 200) { PullEventSubscriptions(); }
        }

// ###END###{EventSubscriptions}

// ###BEGIN###{AuditLog}

        //
        // AUDIT LOG PANEL
        //

        function PullAuditLog(button) {
            if (button == 1 && xxdialogMode) return;
            amtFirstPull |= 32;
            amtstack.Enum('AMT_AuditLog', processAuditLog0);
        }

        var auditLog = null;
        var auditLogEnabledStates = ["Unknown", "Other", "Enabled", "Disabled", "Shutting Down", "Not Applicable", "Enabled but Offline", "In Test", "Deferred", "Quiesce", "Starting"];

        function processAuditLog0(stack, name, responses, status) {
            if (status == 200) {
                QV('go15', true); // Show audit log left panel option

                var r = responses[0]['AuditState'];
                var auditstate = (r & 0x01) ? "Disabled" : "Enabled";
                if (r & 0x02) auditstate += ", Locked";
                if (r & 0x04) auditstate += ", Almost Full";
                if (r & 0x08) auditstate += ", Full";
                if (r & 0x10) auditstate += ", NoKey";

                var x = '<h1>' + "Audit Log Settings" + '</h1>' + TableStart();
                x += TableEntry("State", auditstate);
                x += TableEntry("Storage", responses[0]['CurrentNumberOfRecords'] + " record(s), " + responses[0]['PercentageFree'] + "% free");
                x += TableEntry("Overwrite policy", ((responses[0]['OverwritePolicy'] == 2) ? "Wraps when full" : "Never overwrites"));
                x += TableEnd();
                QH('id_TableAuditLog1', x);

                amtstack.GetAuditLog(processAuditLog1);
            }
        }

        function processAuditLog1(stack, messages) {
            auditLog = messages;
            var i, x = '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px>';
            // ###BEGIN###{!FileSaver}
            x += TableEnd('<div style=float:right><input id=auditFilter placeholder="' + "Filter" + '" style=margin:4px onkeyup=auditFilter()>&nbsp;</div><div> ' + AddRefreshButton('PullAuditLog(1)') + AddButton("Clear Log", 'ClearAuditLog()') /* + AddButton("Settings...", 'ShowAuditLogSettings()')*/) + '<br>';
            // ###END###{!FileSaver}
            // ###BEGIN###{FileSaver}
            x += TableEnd('<div style=float:right><input id=auditFilter placeholder="' + "Filter" + '" style=margin:4px onkeyup=auditFilter()>&nbsp;</div><div> ' + AddRefreshButton('PullAuditLog(1)') + AddButton("Save...", 'SaveAuditLog()') + AddButton("Clear Log", 'ClearAuditLog()') /* + AddButton("Settings...", 'ShowAuditLogSettings()')*/) + '<br>';
            // ###END###{FileSaver}
            if (messages.length == 0) {
                x = "No audit log events found.";
            } else {
                var y = 0;
                x += '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=80px><p><td><td><td>';
                x += '<tr><td class=r1 style=width:110px>&nbsp;&nbsp;<b>' + "Time" + '</b><td class=r1 style=width:260px><b>' + "Initiator" + '</b><td class=r1><b>Action</b>';
                for (i in messages) {
                    var m = messages[i], description = m['AuditApp'], initiator = m['Initiator'];
                    y++;
                    var addr = '';
                    if (m['NetAddress'].length > 0) addr = m['NetAddress'].replace('0000:0000:0000:0000:0000:0000:0000:0001','::1');
                    if (m['Event']) description += ", " + m['Event'];
                    if (m['ExStr'] != null) description += ", " + m['ExStr'];
                    if (initiator != '' && addr != '') initiator += ", ";
                    x += '<tr id=xamtaudit' + i + ' class=r3 onclick=showAuditDetails(' + i + ')><td class=r1 title="' + m['Time'].toLocaleString() + '">&nbsp;&nbsp;' + m['Time'].toLocaleDateString('en', { year: 'numeric', month: '2-digit', day: 'numeric' }) + '<br>&nbsp;&nbsp;' + m['Time'].toLocaleTimeString('en', { hour:'2-digit', minute:'2-digit', second:'2-digit' }) + '<td class=r1>' + initiator + addr + '<td class=r1>' + description;
                }
                x += TableEnd(y == 0 ? '&nbsp;' : '') + '<br>';
            }
            QH('id_TableAuditLog2', x);
        }

        function auditFilter() {
            var filter = Q('auditFilter').value.toLowerCase();
            for (var w in auditLog) { QV('xamtaudit' + w, filter == '' || JSON.stringify(auditLog[w]).toLowerCase().indexOf(filter) >= 0); }
        }

        // ###BEGIN###{FileSaver}
        function SaveAuditLog() {
            if (xxdialogMode || auditLog == null) return;
            SaveJsonFile('IntelAmtAuditlog', 'auditevents', "Intel AMT Audit Log", auditLog);
        }
        // ###END###{FileSaver}

        function ClearAuditLog(x) { QH('id_dialogMessage', "Clear audit log?"); setDialogMode(1, "Audit Log", 3, ClearAuditLogEx); }
        function ClearAuditLogEx() {
            //amtstack.AMT_AuditLog_ClearLog(function () { PullAuditLog(); })
            var handle = amtstack.AMT_AuditLog_SetAuditLock(1,0, handle, function() { amtstack.AMT_AuditLog_ClearLog(function () { amtstack.AMT_AuditLog_SetAuditLock(0, 2, handle, function () { setTimeout(PullAuditLog,1000);}); }); });         
        }

        function ShowAuditLogSettings() {
            if (xxdialogMode) return;
            amtstack.AMT_AuditLog_RequestStateChange(2, 0, AuditLogSettingsCompleted); // Enable
        }

        function AuditLogSettingsCompleted(stack, name, responses, status) {
            if (status == 200) PullAuditLog(); else messagebox("Audit Log", "Error: " + status);
        }

        function showAuditDetails(h) {
            if (xxdialogMode) return;
            var i, m = auditLog[h], x = '<div style=text-align:left>';
            x += addHtmlValue("Time", m['Time'].toLocaleString());
            if (m['Initiator'] != '') x += addHtmlValue("Initiator", m['Initiator']);
            if (m['NetAddress'] != '') x += addHtmlValue("Address", m['NetAddress']);
            x += addHtmlValue("Application", m['AuditApp']);
            x += addHtmlValue("Event", m['Event']);
            if (m['ExStr'] != null) {
                x += addHtmlValue("Extended Data", m['ExStr']);
            } else if (m['Ex'].length > 0) {
                var e = '';
                for (i in m['Ex']) { if (e.length > 0) e += ','; e += m['Ex'].charCodeAt(i); }
                if (e != '') x += addHtmlValue("Data Values", e);
                if (m['Ex'].length > 2 && ReadShort(m['Ex'], 0) == (m['Ex'].length - 2)) x += addHtmlValue("Data String", m['Ex'].substring(2));
            }
            x += '</div>';
            messagebox("Audit Event #" + (h + 1) + " Details", x);
        }

// ###END###{AuditLog}

// ###BEGIN###{Certificates}

        //
        // Certificates
        //

        var xxCertificates = null;
        var xxCertPrivateKeys = null;
        var xxTlsSettings = null;
        var xxTlsCurrentCert = null;
        var xxTLSCredentialContext = null;
        var xxCaPrivateKey = null;
        var xxCaSubjectAttributes = null;

        function PullCertificates() {
            // We only deal with certificates starting with Intel AMT 6 and beyond
            amtstack.BatchEnum(null, ['AMT_PublicKeyCertificate', 'AMT_PublicPrivateKeyPair', 'AMT_TLSSettingData', 'AMT_TLSCredentialContext'], processCerts1);
        }

        function processCerts1(stack, name, responses, status) {
            if ((status == 400) || errcheck(status, stack)) return;
            QV('go16', true); // Security Settings
            xxCertificates = responses['AMT_PublicKeyCertificate'].responses;
            xxCertPrivateKeys = responses['AMT_PublicPrivateKeyPair'].responses;
            xxTlsSettings = responses['AMT_TLSSettingData'].responses;
            xxTLSCredentialContext = responses['AMT_TLSCredentialContext'].responses;

            // Select the current TLS certificate in the drop down box
            xxTlsCurrentCert = null;
            if (xxTLSCredentialContext.length > 0) {
                var certInstanceId = xxTLSCredentialContext[0]['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
                for (var i in xxCertificates) { if (xxCertificates[i]['InstanceID'] == certInstanceId) { xxTlsCurrentCert = i; } }
            }

            // ###BEGIN###{Mode-NodeWebkit}
            try { if ((currentcomputer['tls'] == 0) && (xxTlsSettings[0]['MutualAuthentication'] !== true)) { QV('tlsNotification4', true); } } catch (ex) { console.log(ex); }
            // ###END###{Mode-NodeWebkit}

            // Setup the certificates
            for (var i in xxCertificates) {
                xxCertificates[i].TrustedRootCertficate = (xxCertificates[i]['TrustedRootCertficate'] == true);
                xxCertificates[i].X509Certificate = window.atob(xxCertificates[i]['X509Certificate']);
                xxCertificates[i].XIssuer = parseCertName(xxCertificates[i]['Issuer']);
                xxCertificates[i].XSubject = parseCertName(xxCertificates[i]['Subject']);
            }
            amtcert_linkCertPrivateKey(xxCertificates, xxCertPrivateKeys); // This links all certificates and private keys

            updateCertificates();
        }

        function parseCertName(x) {
            var j, r = {}, xx = x.split(',');
            for (var i in xx) { j = xx[i].indexOf('='); r[xx[i].substring(0, j)] = xx[i].substring(j + 1); }
            return r;
        }

        function getTlsSecurityState(x) {
            if (xxTlsSettings[x]['Enabled'] == false) return "Disabled";
            var r = ((xxTlsSettings[x]['MutualAuthentication'] == true) ? "Mutual-auth TLS" : "Server-auth TLS") + ((xxTlsSettings[x]['AcceptNonSecureConnections'] == true) ? " and non-TLS" : '');
            if ((xxTlsSettings[x]['MutualAuthentication'] == true) && (xxTlsSettings[x]['TrustedCN'])) {
                var trustedCn = MakeToArray(xxTlsSettings[x]['TrustedCN']);
                if (trustedCn.length > 0) { r += ', ' + ((trustedCn.length > 1) ? 'Trusted names' : 'Trusted name') + ': ' + trustedCn.join(', ') + '.'; }
            }
            return r;
        }

        function updateCertificates() {
            if (xxCertificates == null) return;

            // Figure out what index is local & remote
            var localNdx = ((xxTlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);

            // General settings
            var x = TableStart();
            x += TableEntry("Remote TLS security", addLinkConditional(getTlsSecurityState(remoteNdx), 'showSetTlsSecurityDlg()', xxAccountAdminName));
            x += TableEntry("Local TLS security", addLinkConditional(getTlsSecurityState(localNdx), 'showSetTlsSecurityDlg()', xxAccountAdminName));
            x += TableEnd();
            x += '<br>' + TableStart2() + '<tr><td class=r1 style=padding-left:15px><br>' + "Manage Intel&reg; AMT certificates for this computer." + '<br><br>';
            if (xxCertificates.length == 0 && xxCertPrivateKeys.length == 0) {
                x += '<div style=padding-left:15px><br><i>' + "No certificates found." + '</i></div><br>';
            } else {
                for (var i in xxCertificates) {
                    var desc = '';
                    if (xxCertificates[i].TrustedRootCertficate) desc = ", Trusted Root";
                    if (xxCertificates[i].XPrivateKey) desc = ", Private Key";
                    if (i == xxTlsCurrentCert) desc += ", TLS cert";
                    x += '<div class=itemBar onclick=showCertDetails(' + i + ')><div style=padding-top:3px><b>' + EscapeHtml(xxCertificates[i].XSubject['CN']) + '</b><i>' + desc + '</i></div></div>';
                }
                for (var i in xxCertPrivateKeys) {
                    if (!xxCertPrivateKeys[i].XCert) {
                        x += '<div class=itemBar onclick=showKeyPairDetails(' + i + ')><div style=padding-top:3px><i>' + "Unassigned Private Key Pair #" + i + '</i></div></div>';
                    }
                }
            }
            var buttons = AddRefreshButton('PullCertificates()');
            if (xxAccountAdminName) { buttons += (AddButton("Add Certificate...", 'addCertButton()') + AddButton("Issue Certificate...", 'issueCertButton()')); }
            x += '<br><td class=r1>' + TableEnd(buttons);
            QH('id_TableCerts', x);
        }

        function showKeyPairDetails(h) {
            var x = "This is a public/private certificate key pair that does not belong to any certificates. This entry should be temporary.";
            setDialogMode(11, "Key Pair #" + h, 5, function (b) { if (b == 2) { amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertPrivateKeys[h]['InstanceID'] }, PullCertificates, 0, 1); } }, x);
        }

        var xxCertSubjectNames = { 'CN': "Common Name", 'O': "Organization", 'OU': "Org Unit", 'S': "State/Province", 'ST': "State/Province", 'L': "Locality", 'C': "Country", 'SN': "Surname", 'GN': "Given name" };
        function showCertDetails(h) {
            if (xxdialogMode) return;
            var c = xxCertificates[h], x = '<br>';
            // ###BEGIN###{FileSaver}
            x += addHtmlValue("Certificate", c.X509Certificate.length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=downloadCert(' + h + ')>' + "Download" + '</a>');
            // ###END###{FileSaver}
            // ###BEGIN###{!FileSaver}
            x += addHtmlValue("Certificate", c.X509Certificate.length + " bytes");
            // ###END###{!FileSaver}
            x += addHtmlValue("Trusted root", c.TrustedRootCertficate ? "Yes" : "No");
            if (c.TrustedRootCertficate == false && c.XPrivateKey) { x += addHtmlValue("Private key", "Present"); }

            // Show certificate usages
            /*
            y = [];
            if (extKeyUsage != null) {
                if (extKeyUsage.clientAuth == true) { y.push("TLS&nbsp;Client"); }
                if (extKeyUsage.codeSigning == true) { y.push("Code&nbsp;Signing"); }
                if (extKeyUsage.emailProtection == true) { y.push("EMail"); }
                if (extKeyUsage.serverAuth == true) { y.push("TLS&nbsp;Server"); }
                if (extKeyUsage["2.16.840.1.113741.1.2.1"] == true) { y.push("Intel&reg;&nbsp;AMT Console"); }
                if (extKeyUsage["2.16.840.1.113741.1.2.2"] == true) { y.push("Intel&reg;&nbsp;AMT Agent"); }
                if (extKeyUsage["2.16.840.1.113741.1.2.3"] == true) { y.push("Intel&reg;&nbsp;AMT Activation"); }
                if (extKeyUsage.timeStamping == true) { y.push("Time&nbsp;Stamping"); }
                if (y.length > 0) { x += addHtmlValueNoTitle("Certificate Usage", y.join(', ') + '.') + '<br clear=all />'; }
            }
            */

            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Certificate Subject" + '</i></div><br>';
            for (var i in c.XSubject) { if (c.XSubject[i]) { x += addHtmlValue(xxCertSubjectNames[i] ? xxCertSubjectNames[i] : i, EscapeHtml(c.XSubject[i])); } }
            // x += addHtmlValueNoTitle("Fingerprint", c.fingerprint.substring(0,29) + '<br />' + c.fingerprint.substring(30)); // TODO: Parse the certificate using Forge and get the fingerprint
            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Issuer Certificate" + '</i></div><br>';
            for (var i in c.XIssuer) { if (c.XIssuer[i]) { x += addHtmlValue(xxCertSubjectNames[i] ? xxCertSubjectNames[i] : i, EscapeHtml(c.XIssuer[i])); } }
            setDialogMode(11, "Certificate - " + EscapeHtml(c.XSubject['CN']), 5, function (b) {
                if (b == 2) {
                    // If there is a private key, delete it.
                    if (xxCertificates[h].XPrivateKey) amtstack.Delete('AMT_PublicPrivateKeyPair', { 'InstanceID': xxCertificates[h].XPrivateKey['InstanceID'] }, function () { }, 0, 1);
                    // Delete the certificate
                    amtstack.Delete('AMT_PublicKeyCertificate', xxCertificates[h], certificateRemoved, 0, 1);
                }
            }, x);
        }

        // ###BEGIN###{FileSaver}
        function downloadCert(h) { 
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(xxCertificates[h].X509Certificate), xxCertificates[h].XSubject['CN'] + '.cer');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('nwsaveas', xxCertificates[h].XSubject['CN'] + '.cer');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, xxCertificates[h].X509Certificate, 'binary', function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

        function cert_FileSelectHandler(e) {
            haltEvent(e);
            if (e.dataTransfer.files.length == 1) {
                if (e.dataTransfer.files[0].name.toLowerCase().endsWith('.p12')) {
                    issueCertButton(e.dataTransfer.files);
                } else {
                    addCertButton(e.dataTransfer.files);
                }
            }
        }

        var xxDragDropCertFiles = null;
        function addCertButton(files) {
            if (xxdialogMode || !xxAccountAdminName) return;
            var x = '<div style=height:10px></div>', op0 = '', op2 = '';
            xxDragDropCertFiles = files;
            // ###BEGIN###{CertificateManager}
            // ###BEGIN###{PowerControl-Advanced}
            // ###BEGIN###{PowerControl-OneClick}
            if (amtversion > 12) { op2 = '<option value=2>' + "MeshCommander Web Server Root" + '</option>'; }
            // ###END###{PowerControl-OneClick}
            // ###END###{PowerControl-Advanced}
            if (certificateStore.length > 0) { op0 += '<option value=0>' + "Add from certificate manager" + '</option>'; }
            if ((!xxDragDropCertFiles) && ((op0 != '') || (op2 != ''))) { x += '<div style=height:26px;margin-top:4px><select onchange=addCertButtonUpdate() id=certoptype style=float:right;width:260px>' + op0 + '<option value=1>' + "Add from certificate file" + '</option>' + op2 + '</select><div style=padding-top:4px>' + "Operation" + '</div></div>'; }
            x += '<div id=dxcertfileop1>';
            var input = '<input id=certopen onchange=addCertButtonUpdate() type=file style=float:right;width:260px accept=".crt,.cer,.pem">';
            if (xxDragDropCertFiles) { input = '<input style=float:right;width:260px readonly disabled value="' + xxDragDropCertFiles[0].name + '">'; }
            x += '<div style=height:26px;margin-top:4px>' + input + '<div style=padding-top:4px>' + "Certificate file" + '</div></div></div>';
            if (certificateStore.length > 0) {
                x += '<div id=dxcertfileop2><div style=height:26px;margin-top:4px><select id=certhandle style=float:right;width:260px>';
                for (var i in certificateStore) {
                    var certificate = certificateStore[i], name = certificate.cert.subject.getField('CN').value;
                    x += '<option value=' + certificate['h'] + '>' + name + '</option>';
                }
                x += '</select><div style=padding-top:4px>' + "Certificate" + '</div></div></div>';
            }
            // ###END###{CertificateManager}
            // ###BEGIN###{!CertificateManager}
            var input = '<input id=certopen onchange=addCertButtonUpdate() type=file style=float:right;width:260px accept=".cer,.pem">';
            if (xxDragDropCertFiles) { input = '<input style=float:right;width:260px readonly disabled value="' + xxDragDropCertFiles[0].name + '">'; }
            x += '<div style=height:26px;margin-top:4px>' + input + '<div style=padding-top:4px>' + "Certificate file" + '</div></div>';
            // ###END###{!CertificateManager}
            x += '<div style=height:26px;margin-top:4px><select id=certtype style=float:right;width:260px><option value=1>' + "Trusted Root Certificate" + '</option><option value=0>' + "Chain Certificate" + '</option></select><div style=padding-top:4px>' + "Certificate type" + '</div></div>';
            setDialogMode(11, "Add Certificate", 3, addCertButtonOk, x);
            addCertButtonUpdate();
        }

        function addCertButtonUpdate() {
            // ###BEGIN###{CertificateManager}
            if ((!xxDragDropCertFiles) && (certificateStore.length > 0)) {
                QV('dxcertfileop2', Q('certoptype').value == 0);
                QV('dxcertfileop1', Q('certoptype').value == 1);
                if (Q('certoptype').value == 0) { QE('idx_dlgOkButton', true); return; }
            }
            // ###END###{CertificateManager}
            var certopen = getInputElement('certopen');
            QE('idx_dlgOkButton', !certopen || (certopen.files.length == 1) || (Q('certoptype').value == 2));
        }

        function addCertButtonOk() {
            // ###BEGIN###{CertificateManager}
            // ###BEGIN###{PowerControl-Advanced}
            // ###BEGIN###{PowerControl-OneClick}
            if (Q('certoptype').value == 2) {
                var certbin = null;
                if (webserver == null) {
                    webserver = CreateWebServer();
                    webserver.generateCertificate(0);
                    certbin = webserver.rootCert;
                    webserver = null;
                } else {
                    certbin = webserver.rootCert;
                }

                // This is a .PEM file, keep everything between BEGIN/END, clean it up and use as-is. It's already Base64.
                var i = certbin.indexOf('-----BEGIN CERTIFICATE-----');
                if (i >= 0) {
                    certbin = certbin.substring(i + 27);
                    i = certbin.indexOf('-----END CERTIFICATE-----');
                    if (i >= 0) certbin = certbin.substring(0, i)
                    certbin = certbin.replace(/\r\n/g, '');
                    if (getSelectElement('certtype').value == 1) {
                        amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(certbin, certificateAdded);
                    } else {
                        amtstack.AMT_PublicKeyManagementService_AddCertificate(certbin, certificateAdded);
                    }
                }
                return;
            }
            // ###END###{PowerControl-OneClick}
            // ###END###{PowerControl-Advanced}
            if ((xxDragDropCertFiles) || (certificateStore.length == 0) || (Q('certoptype').value == 1)) {
                var certopen = getInputElement('certopen');
                var files = xxDragDropCertFiles;
                if (certopen) files = certopen.files;
                if (files && files.length == 1) {
                    var reader = new FileReader();
                    reader.onload = addCertButtonOk2;
                    reader.readAsBinaryString(files[0]);
                }
            } else {
                var certificate = getCertificate(Q('certhandle').value)
                if (getSelectElement('certtype').value == 1) {
                    amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(certificate['certbin'], certificateAdded);
                } else {
                    amtstack.AMT_PublicKeyManagementService_AddCertificate(certificate['certbin'], certificateAdded);
                }
            }
            // ###END###{CertificateManager}
            // ###BEGIN###{!CertificateManager}
            var certopen = getInputElement('certopen');
            var files = xxDragDropCertFiles;
            if (certopen) files = certopen.files;
            if (files && files.length == 1) {
                var reader = new FileReader();
                reader.onload = addCertButtonOk2;
                reader.readAsBinaryString(files[0]);
            }
            // ###END###{!CertificateManager}
        }
        
        function addCertButtonOk2(file) {
            var data = file.target.result;
            var i = data.indexOf('-----BEGIN CERTIFICATE-----');
            if (i >= 0) {
                // This is a .PEM file, keep everything between BEGIN/END, clean it up and use as-is. It's already Base64.
                data = data.substring(i + 27);
                i = data.indexOf('-----END CERTIFICATE-----');
                if (i >= 0) data = data.substring(0, i)
                data = data.replace(/\r\n/g, '');
            } else {
                // This is a .CER file, just base64 encode it and we should be ok.
                data = btoa(data);
            }
            if (getSelectElement('certtype').value == 1) {
                amtstack.AMT_PublicKeyManagementService_AddTrustedRootCertificate(data, certificateAdded);
            } else {
                amtstack.AMT_PublicKeyManagementService_AddCertificate(data, certificateAdded);
            }
        }

        function issueCertButton(files) {
            if (xxdialogMode || !xxAccountAdminName) return;
            xxDragDropCertFiles = files;

            // ###BEGIN###{CertificateManager}
            var x = '', certCount = getCertificateWithKeyCount();
            if ((!xxDragDropCertFiles) && (certCount > 0)) { x += '<div style=height:26px;margin-top:4px><select onchange=addCertButtonUpdate() id=certoptype style=float:right;width:230px><option value=0>' + "Issue from certificate manager" + '</option><option value=1>' + "Issue from certificate file" + '</option></select><div style=padding-top:4px>Operation</div></div>'; }
            x += '<div id=dxcertfileop1>', input = '<input id=certopen onchange=issueCertButtonUpdate() type=file style=float:right;width:230px accept=".p12">';
            if (xxDragDropCertFiles) { input = '<input style=float:right;width:230px readonly disabled value="' + xxDragDropCertFiles[0].name + '">'; }
            x += '<div style=height:26px;margin-top:4px>' + input + '<div style=padding-top:4px>' + "Certificate file" + '</div></div><div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certopenpass type=password autocomplete=off style=float:right;width:230px><div style=padding-top:4px>' + "Certificate password" + '</div></div></div>';
            if (certificateStore.length > 0) {
                x += '<div id=dxcertfileop2><div style=height:26px;margin-top:4px><select id=certhandle style=float:right;width:230px>';
                for (var i in certificateStore) {
                    var certificate = certificateStore[i], name = certificate.cert.subject.getField('CN').value
                    if (certificate['privateKey']) { x += '<option value=' + certificate['h'] + '>' + name + '</option>'; }
                }
                x += '</select><div style=padding-top:4px>' + "Certificate" + '</div></div></div>';
            }
            // ###END###{CertificateManager}

            // ###BEGIN###{!CertificateManager}
            var x = '', input = '<input id=certopen type=file style=float:right;width:230px onchange=issueCertButtonUpdate() accept=".p12">';
            if (xxDragDropCertFiles) { input = '<input style=float:right;width:230px readonly disabled value="' + xxDragDropCertFiles[0].name + '">'; }
            x += '<div styleheight:26px;margin-top:14px>' + input + '<div style=padding-top:4px>Certificate file</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certopenpass type=password autocomplete=off style=float:right;width:230px><div style=padding-top:4px>' + "Certificate password" + '</div></div>';
            // ###END###{!CertificateManager}

            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Intel&reg; AMT Certificate" + '</i></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certcn style=float:right;width:230px><div style=padding-top:4px>' + "Common Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certo style=float:right;width:230px><div style=padding-top:4px>' + "Organization" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certst style=float:right;width:230px><div style=padding-top:4px>' + "State/Province" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=issueCertButtonUpdate() id=certc style=float:right;width:230px><div style=padding-top:4px>' + "Country" + '</div></div>';
            x += '<div>' + "Certificate Usages" + '</div><ul style="list-style-type:none;height:100px;overflow:auto;width:100%;border: 1px solid #000;background-color:white;overflow-x:hidden;margin:0;padding:0">';
            //x += '<li><label><input type=checkbox id=d11_cu1>' + "Intel&reg; AMT Console" + '</label></li>';
            //x += '<li><label><input type=checkbox id=d11_cu2>' + "Intel&reg; AMT Agent" + '</label></li>';
            //x += '<li><label><input type=checkbox id=d11_cu3>' + "Intel&reg; AMT Activation" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu4 checked>' + "TLS Server (HTTPS)" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu5>' + "TLS Client (HTTPS)" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu6>' + "Email Protection" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu7>' + "Code Signing" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu8>' + "Time Stamp" + '</label></li>';
            x += '</ul>';
            setDialogMode(11, "Issue Certificate", 3, issueCertButtonOk, x);
            issueCertButtonUpdate();
        }

        function issueCertButtonUpdate() {
            // ###BEGIN###{CertificateManager}
            var certCount = getCertificateWithKeyCount();
            if ((!xxDragDropCertFiles) && (certCount > 0)) {
                QV('dxcertfileop2', Q('certoptype').value == 0);
                QV('dxcertfileop1', Q('certoptype').value == 1);
                QE('idx_dlgOkButton', (getInputElement('certcn').value != '') && (getInputElement('certo').value != '') && (getInputElement('certst').value != '') && (getInputElement('certc').value != ''));
                return;
            }
            // ###END###{CertificateManager}
            var certopen = getInputElement('certopen');
            QE('certopenpass', !certopen || (certopen && certopen.files.length == 1));
            var x = (!certopen || certopen.files.length < 2);
            if ((!certopen || (certopen && certopen.files.length)) == 1 && Q('certopenpass').value == '') x = false;
            if (getInputElement('certcn').value == '' || getInputElement('certo').value == '' || getInputElement('certst').value == '' || getInputElement('certc').value == '') { x = false; }
            QE('idx_dlgOkButton', x);
        }

        function issueCertButtonOk() {
            // ###BEGIN###{CertificateManager}
            if ((xxDragDropCertFiles) || (certificateStore.length == 0) || (Q('certoptype').value == 1)) {
                var certopen = getInputElement('certopen');
                var files = xxDragDropCertFiles;
                if (certopen) files = certopen.files;
                if (files && files.length == 1) {
                    // Issue a certificate using this file
                    var reader = new FileReader();
                    reader.onload = issueCertButtonOk2;
                    reader.readAsBinaryString(files[0]);
                } else {
                    // Issue a certificate using a dummy CA
                    issueCertButtonOk3(null);
                }
            } else {
                // Save the certificate store certificate as a p12 and load it back up using the regular user flow. This makes the code smaller but slower.
                var certificate = getCertificate(Q('certhandle').value);
                var certBase64 = forge.util.encode64(forge.asn1.toDer(forge.pkcs12.toPkcs12Asn1(certificate['privateKey'], certificate['cert'], 'pass')).getBytes());
                amtcert_loadP12File(atob(certBase64), 'pass', issueCertButtonOk3);
            }
            // ###END###{CertificateManager}
            // ###BEGIN###{!CertificateManager}
            var certopen = getInputElement('certopen');
            var files = xxDragDropCertFiles;
            if (certopen) files = certopen.files;
            if (files && files.length == 1) {
                // Issue a certificate using this file
                var reader = new FileReader();
                reader.onload = issueCertButtonOk2;
                reader.readAsBinaryString(files[0]);
            } else {
                // Issue a certificate using a dummy CA
                issueCertButtonOk3(null);
            }
            // ###END###{!CertificateManager}
        }

        function issueCertButtonOk2(file) {
            // Load the CA certificate and private key
            var r = amtcert_loadP12File(file.target.result, Q('certopenpass').value, issueCertButtonOk3);
            if (r == false) { messagebox("Issue Certificate", "Unable to decrypt/decode certificate."); return; }
        }

        function issueCertButtonOk3(privateKey, subjectAttributes, cert) {
            // Ask Intel AMT to generate a key pair
            xxCaPrivateKey = privateKey;
            xxCaSubjectAttributes = subjectAttributes;
            amtstack.AMT_PublicKeyManagementService_GenerateKeyPair(0, 2048, GenerateKeyPairResponse);
        }

        function GenerateKeyPairResponse(stack, serviceName, response, status) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }
            if (response.Body['ReturnValue'] != 0) { messagebox("Issue Certificate", "Failed to generate key pair, " + response.Body['ReturnValueStr']); return; }

            // Get the new key pair
            amtstack.Enum('AMT_PublicPrivateKeyPair', GenerateKeyPairResponse2, response.Body['KeyPair']['ReferenceParameters']['SelectorSet']['Selector']['Value']);
        }

        function GenerateKeyPairResponse2(stack, serviceName, response, status, tag) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }
            var DERKey = null;
            for (var i in response) { if (response[i]['InstanceID'] == tag) DERKey = response[i]['DERKey']; }

            // Get certificate values
            var certattributes = { 'CN': getInputElement('certcn').value, 'O': getInputElement('certo').value, 'ST': getInputElement('certst').value, 'C': getInputElement('certc').value };
            var issuerattributes = { 'CN': "Untrusted Root Certificate" };
            if (xxCaPrivateKey != null && xxCaSubjectAttributes) {
                issuerattributes = {};
                for (var i in xxCaSubjectAttributes) {
                    issuerattributes[xxCaSubjectAttributes[i].shortName] = xxCaSubjectAttributes[i].value; // The issuing CA's subject attributes 
                }
            } 

            // Figure out the extended key usages
            var extKeyUsage = { name: 'extKeyUsage' }
            //if (Q('d11_cu1').checked) { extKeyUsage['2.16.840.1.113741.1.2.1'] = true; extKeyUsage.clientAuth = true; }
            //if (Q('d11_cu2').checked) { extKeyUsage['2.16.840.1.113741.1.2.2'] = true; extKeyUsage.clientAuth = true; }
            //if (Q('d11_cu3').checked) { extKeyUsage['2.16.840.1.113741.1.2.3'] = true; extKeyUsage.clientAuth = true; }
            if (Q('d11_cu4').checked) { extKeyUsage.serverAuth = true; }
            if (Q('d11_cu5').checked) { extKeyUsage.clientAuth = true; }
            if (Q('d11_cu6').checked) { extKeyUsage.emailProtection = true; }
            if (Q('d11_cu7').checked) { extKeyUsage.codeSigning = true; }
            if (Q('d11_cu8').checked) { extKeyUsage.timeStamping = true; }

            // Sign the key pair using the CA certifiate
            var cert = amtcert_signWithCaKey(DERKey, xxCaPrivateKey, certattributes, issuerattributes, extKeyUsage);
            if (cert == null) { messagebox("Issue Certificate", "Unable to sign certificate."); return; }

            // Place the resulting signed certificate back into AMT
            var pem = forge.pki.certificateToPem(cert).replace(/(\r\n|\n|\r)/gm, '');
            amtstack.AMT_PublicKeyManagementService_AddCertificate(pem.substring(27, pem.length - 25), GenerateKeyPairResponse4);
        }

        function GenerateKeyPairResponse4(stack, serviceName, response, status) {
            if (status != 200) { messagebox("Issue Certificate", "Failed to generate key pair. Status: " + status); return; }
            PullCertificates();
        }

        function certificateAdded(stack, serviceName, response, status) { if (status != 200 || response.Body['ReturnValue'] != 0) { messagebox("Add Certificate", "Unable to add certificate, error " + (status != 200 ? status : response.Body['ReturnValueStr'])); } else PullCertificates(); }
        function certificateRemoved(stack, serviceName, header, status) { if (status != 200) { messagebox("Remove Certificate", "Unable to remove certificate, error " + status); } else PullCertificates(); }

        function getInputElement(id) { var allelements = document.getElementsByTagName('input'); for (t = 0; t < allelements.length; t++) { if (allelements[t].id == id) return allelements[t]; } }
        function getSelectElement(id) { var allelements = document.getElementsByTagName('select'); for (t = 0; t < allelements.length; t++) { if (allelements[t].id == id) return allelements[t]; } }

        function showSetTlsSecurityDlg(x) {
            if (xxdialogMode) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><select onchange=showSetTlsSecurityDlgUpdate() id=tlscert style=float:right;width:260px><option value=-1>' + "No Certificate, TLS Disabled" + '</option>';
            for (var i in xxCertificates) { if (xxCertificates[i].TrustedRootCertficate == false && xxCertificates[i].XPrivateKey) { x += '<option value=' + i + '>' + xxCertificates[i].XSubject['CN'] + '</option>'; } }
            x += '</select><div style=padding-top:4px>' + "Certificate" + '</div></div>';

            x += '<div style=height:26px;margin-top:4px><select id=tlsremote style=float:right;width:260px onchange=showSetTlsSecurityDlgUpdate()><option value=0>Server-auth TLS only</option><option value=1>Server-auth, non-TLS allowed</option>';
            x += '<option value=2>Mutual-auth TLS only</option><option value=3>Mutual-auth, non-TLS allowed</option>'; // Support for mutual-auth TLS seems to have been removed on AMT8 and after ??
            x += '</select><div style=padding-top:4px>Security</div></div><div style=height:26px id=d11rcn title="' + "Comma seperated list of certificate common names that will be allowed to connect remotely." + '"><input id=d11_rcn style=float:right;width:260px onkeyup=showSetTlsSecurityDlgUpdate() placeholder="' + "name1, name2" + '"><div style=padding-top:4px>' + "Remote CN\'s" + '</div></div>';

            setDialogMode(11, "TLS Settings", 3, showSetTlsSecurityDlgOk, x);

            // Select the current TLS certificate in the drop down box
            if ((xxTLSCredentialContext.length == 0) || (xxTlsSettings[0]['Enabled'] == false) || (xxTlsSettings[1]['Enabled'] == false)) {
                getSelectElement('tlscert').value = -1;
            } else {
                var certInstanceId = xxTLSCredentialContext[0]['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
                for (var i in xxCertificates) { if (xxCertificates[i]['InstanceID'] == certInstanceId) { getSelectElement('tlscert').value = i; } }
            }

            // Figure out what index is local & remote
            var localNdx = ((xxTlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);

            // Select correct TLS options in the drop down boxes
            getSelectElement('tlsremote').value = ((xxTlsSettings[remoteNdx]['MutualAuthentication'] == true) ? 2 : 0) + ((xxTlsSettings[remoteNdx]['AcceptNonSecureConnections'] == true) ? 1 : 0);
            if (xxTlsSettings[remoteNdx]['TrustedCN']) { Q('d11_rcn').value = MakeToArray(xxTlsSettings[remoteNdx]['TrustedCN']).join(', '); }

            showSetTlsSecurityDlgUpdate();
        }

        function showSetTlsSecurityDlgUpdate() {
            var h = getSelectElement('tlscert').value;
            QE('tlsremote', h != -1);
            QV('d11rcn', (h != -1) && (getSelectElement('tlsremote').value > 1));
            var ok = true;
            if ((getSelectElement('tlsremote').value > 1) && (!splitDomains(Q('d11_rcn').value))) { ok = false; }
            QE('idx_dlgOkButton', ok);
        }

        var setTlsSecurityPendingCalls;
        var setTlsSecurityDeleteCredentialContext;
        function showSetTlsSecurityDlgOk() {
            var h = getSelectElement('tlscert').value;
            var r = getSelectElement('tlsremote').value;
            var xxTlsSettings2 = Clone(xxTlsSettings);
            setTlsSecurityPendingCalls = 0;
            setTlsSecurityDeleteCredentialContext = null;

            if (h != -1) {
                // Set the TLS certificate
                if (xxTLSCredentialContext.length > 0) {
                    // Modify the current context
                    var newTLSCredentialContext = Clone(xxTLSCredentialContext[0]);
                    newTLSCredentialContext['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'] = xxCertificates[h]['InstanceID'];
                    amtstack.Put('AMT_TLSCredentialContext', newTLSCredentialContext, setTlsSecurityResponse, 0, 1);
                    setTlsSecurityPendingCalls++;
                } else {
                    // Add a new security context
                    amtstack.Create('AMT_TLSCredentialContext', {
                        'ElementInContext':'<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + xxCertificates[h]['InstanceID'] + '</w:Selector></w:SelectorSet></a:ReferenceParameters>',
                        'ElementProvidingContext':'<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_TLSProtocolEndpointCollection') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="ElementName">TLSProtocolEndpointInstances Collection</w:Selector></w:SelectorSet></a:ReferenceParameters>' }, setTlsSecurityResponse);
                    setTlsSecurityPendingCalls++;
                }
            } else {
                // Clear the TLS certificate association (MOVE THIS)
                if (xxTLSCredentialContext.length > 0) { setTlsSecurityDeleteCredentialContext = Clone(xxTLSCredentialContext[0]); }
            }

            // Figure out what index is local & remote
            var localNdx = ((xxTlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);

            // Remote TLS settings
            xxTlsSettings2[remoteNdx]['Enabled'] = (h != -1);
            xxTlsSettings2[remoteNdx]['MutualAuthentication'] = (r >= 2);
            xxTlsSettings2[remoteNdx]['AcceptNonSecureConnections'] = ((r % 2) == 1);
            xxTlsSettings2[remoteNdx]['TrustedCN'] = splitDomains(Q('d11_rcn').value);
            
            // Local TLS settings
            xxTlsSettings2[localNdx]['Enabled'] = (h != -1);
            xxTlsSettings2[localNdx]['TrustedCN'] = splitDomains(Q('d11_rcn').value); // This is required for old Intel AMT (v7 for sure) because older AMT support local interface mutual-auth and don't well if you don't set this.

            // Mutual-auth TLS requires time sync
            if (r >= 2) {
                setTlsSecurityPendingCalls++;
                amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(function (stack, name, response, status) {
                    if (status != 200) { messagebox('', "Failed to set time, status = " + status); return; }
                    if (response.Body['ReturnValue'] != 0) { messagebox('', "Failed to set time, error: " + response.Body['ReturnValueStr']); return; }
                    //var now = new Date(), Tm1 = Math.round((now.getTime() - (now.getTimezoneOffset() * 60000)) / 1000);
                    var now = new Date(), Tm1 = Math.round(now.getTime() / 1000);
                    amtstack.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch(response.Body['Ta0'], Tm1, Tm1, function () { setTlsSecurityResponse(); });
                });
            }

            // Update TLS settings
            setTlsSecurityPendingCalls += 2;
            amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[0], setTlsSecurityResponse, 0, 1, xxTlsSettings2[0]);
            amtstack.Put('AMT_TLSSettingData', xxTlsSettings2[1], setTlsSecurityResponse, 0, 1, xxTlsSettings2[1]);

            statusbox("TLS Settings", "Applying new security settings...");
        }

        // Split a string into a array of domains. Return null if not a valid list.
        function splitDomains(str) {
            str = str.split(',');
            if (str.length == 0) return;
            for (var i in str) { str[i] = str[i].trim(); if ((str[i].indexOf(' ') >= 0) || (str[i].length == 0)) return; }
            if (str.length > 4) return;
            return str;
        }

        function setTlsSecurityResponse(stack, name, response, status) {
            if (stack) {
                if (status != 200) { messagebox('', "Failed to set TLS security, status = " + status); return; }
                if (response.Body['ReturnValueStr'] && !methodcheck(response)) return;
            }

            // Check if all the calls are done & perform a commit
            if ((--setTlsSecurityPendingCalls) == 0) { amtstack.AMT_SetupAndConfigurationService_CommitChanges(null, setTlsSecurityResponse2); }
        }

        function setTlsSecurityResponse2(stack, name, response, status) {
            if (status != 200) { messagebox('', "Failed to set TLS security, status = " + status); return; }
            if (response.Body['ReturnValue'] != 0) { messagebox('', "Failed to set TLS security, error: " + response.Body['ReturnValueStr']); return; }
            setTimeout(setTlsSecurityResponse3, 2000);
        }

        function setTlsSecurityResponse3() {
            if (setTlsSecurityDeleteCredentialContext != null) { amtstack.Delete('AMT_TLSCredentialContext', setTlsSecurityDeleteCredentialContext, function () { }); }
            PullCertificates();
            setDialogMode();
            amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(processSystemTime);
        }

// ###END###{Certificates}

// ###BEGIN###{AgentPresence}

        //
        // AGENT PRESENCE
        //

        var xxWatchdog = null;

        function PullWatchdog() {
            amtstack.BatchEnum(null, ['*AMT_AgentPresenceCapabilities', 'AMT_AgentPresenceWatchdog', 'AMT_AgentPresenceWatchdogAction', 'AMT_StateTransitionCondition', 'CIM_ConcreteDependency'], PullWatchdogResponse);
        }

        function PullWatchdogResponse(stack, name, responses, status) {
            if ((status == 200) && (responses['AMT_AgentPresenceCapabilities'].status == 200)) {
                xxWatchdog = responses;
            
                // Place the actions into the watchdogs for easy navigation.
                for (var i in xxWatchdog['CIM_ConcreteDependency'].responses) {
                    var link = xxWatchdog['CIM_ConcreteDependency'].responses[i];
                    var x1 = getItem(link['Antecedent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'CreationClassName');
                    if (x1 && x1['Value'] == 'AMT_AgentPresenceWatchdog') {
                        var deviceid = getItem(link['Antecedent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'DeviceID')['Value'];
                        var policyConditionName = getItem(link['Dependent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyConditionName')['Value'];
                        var watchdog = getItem(xxWatchdog['AMT_AgentPresenceWatchdog'].responses, 'DeviceID', deviceid);
                        var transitionPolicy = getItem(xxWatchdog['AMT_StateTransitionCondition'].responses, 'PolicyConditionName', policyConditionName);
                        if (!watchdog.transitions) watchdog.transitions = [];
                        watchdog.transitions.push(transitionPolicy);
                    }
                    if (x1 && x1['Value'] == 'AMT_StateTransitionCondition') {
                        var policyConditionName = getItem(link['Antecedent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyConditionName')['Value'];
                        var policyActionName = getItem(link['Dependent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyActionName')['Value'];
                        var transitionPolicy = getItem(xxWatchdog['AMT_StateTransitionCondition'].responses, 'PolicyConditionName', policyConditionName);
                        var watchdogAction = getItem(xxWatchdog['AMT_AgentPresenceWatchdogAction'].responses, 'PolicyActionName', policyActionName);
                        if (!transitionPolicy.actions) transitionPolicy.actions = [];
                        transitionPolicy.actions.push(watchdogAction);
                    }
                }

                updateWatchdog();
                QV('go19', true); // Show Agent Presence panel
            }
        }

        var watchdogEnabledStates = [ "Unknown", "Other", "Enabled", "Disabled", "Shutting Down", "Not Applicable", "Enabled but Offline", "In Test", "Deferred", "Quiesce", "Starting" ];
        var watchdogMonitoredEntity = [ "Unknown", "Other", "Operating System", "Operating System Boot Process", "Operating System Shutdown Process", "Firmware Boot Process", "BIOS Boot Process", "Application", "Service Processor" ];
        function updateWatchdog() {
            if (xxWatchdog == null) return;
            var x = '';

            // Global Agent Presense Values
            x += TableStart();
            x += TableEntry("Maximum Watchdogs", xxWatchdog['AMT_AgentPresenceCapabilities'].response['MaxTotalAgents'] + " watchdogs");
            x += TableEntry("Maximum Total Actions", xxWatchdog['AMT_AgentPresenceCapabilities'].response['MaxTotalActions'] + " actions");
            // x += TableEntry("Maximum EAC Watchdogs", xxWatchdog['AMT_AgentPresenceCapabilities'].response['MaxEacAgents'] + " watchdogs");
            x += TableEnd() + '<br>';

            // Watchdogs
            x += TableStart2();
            x += '<tr><td class=r1 style=padding-left:15px><br>' + "Manage Intel&reg; AMT agent presence watchdogs." + '<br><br>';
            if ((xxWatchdog['AMT_AgentPresenceWatchdog'].responses == null) || (xxWatchdog['AMT_AgentPresenceWatchdog'].responses.length == 0)) {
                x += '<div style=padding-left:15px><i>' + "No agent presence watchdog found." + '</i></div><br>';
            } else {
                for (var i in xxWatchdog['AMT_AgentPresenceWatchdog'].responses) {
                    var w = xxWatchdog['AMT_AgentPresenceWatchdog'].responses[i];
                    var n = guidToStr(rstr2hex(atob(w['DeviceID'])));
                    if (w['MonitoredEntityDescription'] && w['MonitoredEntityDescription'] != '') n = EscapeHtml(w['MonitoredEntityDescription']);
                    x += '<div class=itemBar onclick=showWatchdogDetails(' + i + ')><input type=button style=float:right value="' + "Add Action..." + '" onclick=addWatchdogAction(event,' + i + ')>';
                    if (w.transitions) { x += '<input type=button style=float:right value="' + "Delete Actions..." + '" onclick=deleteWatchdogActions(event,' + i + ')>'; }
                    x += '<div style=padding-top:3px><b>' + n + '</b>, ' + amtstack.WatchdogCurrentStates[w['CurrentState']] + '</div>';
                    var xx = '';
                    for (var j in w.transitions) {
                        var t = w.transitions[j];
                        if (xx != '') xx += '<br>';
                        xx += getWatchdogTransitionStr(t['OldState']) + ' &rarr; ' + getWatchdogTransitionStr(t['NewState']);
                        if (t.actions) {
                            var action = t.actions[0];
                            if (action['EventOnTransition'] == true) { xx += " : Event to log"; }
                        }
                    }
                    if (xx != '') { x += '<div style=padding:12px>' + xx + '</div>'; }
                    x += '</div>';
                }
            }
            x += '<br>';
            x += TableEnd(AddRefreshButton('PullWatchdog()') + AddButton("Add Watchdog...", 'AddWatchdog()'));
            x += '<br>';

            QH('id_TableSystemAgentPresence', x);
        }

        function getWatchdogTransitionStr(s) {
            if (s == 31) return "Any State";
            var x = '';
            for (var i in amtstack.WatchdogCurrentStates) { if ((s & i) != 0) { x += ', ' + amtstack.WatchdogCurrentStates[i]; } }
            return x.substring(2);
        }

        function showWatchdogDetails(i) {
            var w = xxWatchdog['AMT_AgentPresenceWatchdog'].responses[i];

            var x = '';
            //x += addHtmlValue("DeviceID", guidToStr(rstr2hex(atob(w['DeviceID']))));
            if (w['MonitoredEntityDescription'] && w['MonitoredEntityDescription'] != '') x += addHtmlValue("Description", EscapeHtml(w['MonitoredEntityDescription']));
            x += addHtmlValue("Monitored Entity", watchdogMonitoredEntity[w['MonitoredEntity']]);
            x += addHtmlValue("Current State", amtstack.WatchdogCurrentStates[w['CurrentState']]);
            x += addHtmlValue("Enabled State", watchdogEnabledStates[w['EnabledState']]);
            x += addHtmlValue("Startup Interval", w['StartupInterval'] + " second(s)");
            x += addHtmlValue("Timeout Interval", w['TimeoutInterval'] + " second(s)");

            setDialogMode(11, format("Watchdog {0}", guidToStr(rstr2hex(atob(w['DeviceID'])))), 5, showWatchdogDetailsOk, x, w);
        }

        function showWatchdogDetailsOk(x, w) {
            if (x == 2) {
                amtstack.Delete('AMT_AgentPresenceWatchdog', { 'DeviceID': w['DeviceID'] }, PullWatchdog);
            }
        }

        function AddWatchdog() {
            var x = '';
            x += '<div style=height:26px;margin-top:4px><input id=wgname style=float:right;width:240px maxlength=16 onkeyup=AddWatchdogUpdate()><div style=padding-top:4px>' + "Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=wgguid style=float:right;width:240px maxlength=36 onkeyup=AddWatchdogUpdate()><div style=padding-top:4px title="' + "Generate random DeviceID" + '">' + addLink("DeviceID", 'GenerateWatchdogGuid()') + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=wgstart style=float:right;width:240px maxlength=8 placeholder=3600 onkeyup=AddWatchdogUpdate()><div style=padding-top:4px>' + "Startup (seconds)" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input id=wgtimeout style=float:right;width:240px maxlength=8 placeholder=60 onkeyup=AddWatchdogUpdate()><div style=padding-top:4px>' + "Timeout (seconds)" + '</div></div>';
            setDialogMode(11, "Add Watchdog", 3, AddWatchdogOk, x);
            AddWatchdogUpdate();
        }

        function GenerateWatchdogGuid() {
            var i, guid = '';
            for (i = 0; i < 16; i++) { guid += String.fromCharCode(random(255)); }
            Q('wgguid').value = guidToStr(rstr2hex(guid));
            AddWatchdogUpdate();
        }

        function AddWatchdogUpdate() {
            var ok = (Q('wgstart').value == '' || parseInt(Q('wgstart').value) > 0) && (Q('wgtimeout').value == '' || parseInt(Q('wgtimeout').value) > 0);
            var gc = 0, g = Q('wgguid').value.toLowerCase();
            for (var i = 0; i < g.length; i++) {
                var c = g.charCodeAt(i);
                if (c == 45) continue;
                if ((c >= 48 && c <= 57) || (c >= 97 && c <= 102)) { gc++; } else { ok = false; }
            }
            if (gc != 32) ok = false;
            QE('dlgOkButton', ok);
        }

        function AddWatchdogOk() {
            var timeout = Q('wgtimeout').value, startup = Q('wgstart').value;
            if (timeout == '') timeout = 60;
            if (startup == '') startup = 3600;
            var guid = btoa(hex2rstr(guidToStr(Q('wgguid').value.replace(/-/g, '')).replace(/-/g, '')));
            var wdog = { 'CreationClassName': 0, 'DeviceID': guid, 'StartupInterval': startup, 'SystemCreationClassName': 0, 'SystemName': 0, 'TimeoutInterval': timeout, 'MonitoredEntityDescription': Q('wgname').value };
            amtstack.Create('AMT_AgentPresenceWatchdog', wdog, AddWatchdogOk2);
        }

        function AddWatchdogOk2(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Watchdog", "Unable to add watchdog, error #" + status);
            } else {
                PullWatchdog();
            }
        }

        function addWatchdogAction(e, i) {
            var w = xxWatchdog['AMT_AgentPresenceWatchdog'].responses[i];
            var x = '<table>';
            x += '<td style=width:180px>' + "From" + '<br>'
            for (var i in amtstack.WatchdogCurrentStates) {
                x += '<input id=wgsa' + i + ' type=checkbox onclick=addWatchdogActionUpdate()> ' + amtstack.WatchdogCurrentStates[i] + '<br />';
            }
            x += '<td>' + "To" + '<br>'
            for (var i in amtstack.WatchdogCurrentStates) {
                x += '<input id=wgsb' + i + ' type=checkbox onclick=addWatchdogActionUpdate()> ' + amtstack.WatchdogCurrentStates[i] + '<br />';
            }
            x += '</table><br>' + "Perform Action" + '<br><input id=wgsevent type=checkbox checked onclick=addWatchdogActionUpdate()>' + "Write to event log" + '<br />';
            setDialogMode(11, "Add Watchdog Action", 3, addWatchdogActionOk, x, w);
            addWatchdogActionUpdate();
            haltEvent(e);
        }

        function addWatchdogActionUpdate() {
            var tfrom = 0, tto = 0;
            for (var i in amtstack.WatchdogCurrentStates) {
                if (Q('wgsa' + i).checked == true) tfrom += parseInt(i);
                if (Q('wgsb' + i).checked == true) tto += parseInt(i);
            }
            QE('dlgOkButton', tfrom > 0 && tto > 0 && Q('wgsevent').checked == true);
        }

        function addWatchdogActionOk(b, w) {
            var tfrom = 0, tto = 0;
            for (var i in amtstack.WatchdogCurrentStates) {
                if (Q('wgsa' + i).checked == true) tfrom += parseInt(i);
                if (Q('wgsb' + i).checked == true) tto += parseInt(i);
            }
            amtstack.AMT_AgentPresenceWatchdog_AddAction(tfrom, tto, Q('wgsevent').checked, null, null, AddWatchdogActionResponse, null, 0, { 'DeviceID': w['DeviceID'] });
        }

        function AddWatchdogActionResponse(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Watchdog Action", "Unable to add watchdog action, error #" + status);
            } else {
                PullWatchdog();
            }
        }

        function deleteWatchdogActions(e, i) {
            var w = xxWatchdog['AMT_AgentPresenceWatchdog'].responses[i];
            setDialogMode(11, "Delete Watchdog Actions", 3, deleteWatchdogActionsOk, "Delete all actions for this watchdog?", w);
            haltEvent(e);
        }

        function deleteWatchdogActionsOk(b, w) {
            amtstack.AMT_AgentPresenceWatchdog_DeleteAllActions(deleteWatchdogActionResponse, null, 0, { 'DeviceID': w['DeviceID'] });
        }

        function deleteWatchdogActionResponse(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Watchdog Action", "Unable to remove watchdog actions, error #" + status);
            } else {
                PullWatchdog();
            }
        }

// ###END###{AgentPresence}
        
// ###BEGIN###{SystemDefense}

        //
        // SYSTEM DEFENSE PANEL
        //

        var xxSystemDefense = null;
        var xxSystemDefenceLinkedPolicy = {};
        var xxUpdatingDefenseStats = false;
        var xxFilterStatistics = [{}, {}]; // Wired and wireless interface stats
        var xxFilterStatisticsTimer = null;
        var xxFilterStatisticsTimerActive = false;

        var xxSystemDefenceFilterEthernetTypes = { 2048: "All IP Packets", 2054: "All ARP Packets" };
        var xxSystemDefenceFilterIPTypes = { 4: "IPv4", 6: "IPv6" };
        var xxSystemDefenceFilterDesc = { 0: "Allow, Count", 1: "Drop, Count", 2: "Rate limit", 3: "Allow", 4: "Drop" };
        var xxSystemDefenceFilters = { 'HdrProtocolID': 1, 'HdrDestAddress': 2, 'HdrDestMask': 2, 'HdrSrcAddress': 2, 'HdrSrcMask': 2, 'HdrSrcPortStart': 1, 'HdrSrcPortEnd': 1, 'HdrDestPortStart': 1, 'HdrDestPortEnd': 1, 'HdrSrcAddressEndOfRange': 2, 'HdrDestAddressEndOfRange ': 2, 'TCPFlagsOn': 3, 'TCPFlagsOff': 3 };

        function PullSystemDefense() {
            amtFirstPull |= 4;
            amtstack.BatchEnum(null, ['AMT_SystemDefensePolicy', 'AMT_NetworkPortSystemDefensePolicy', 'AMT_Hdr8021Filter', 'AMT_IPHeadersFilter', 'AMT_NetworkFilter'], PullSystemDefenseResponse);
        }

        function PullSystemDefenseResponse(stack, name, responses, status) {
            if (status == 200) {
                xxSystemDefense = responses;
                updateSystemDefense();
                QV('go18', true); // Show System Defense Panel
                if (urlvars['norefresh']) { UpdateDefenseStats(); } // If norefresh is set, pull the system defense stats now.
            }
        }

        function updateSystemDefense() {
            if (xxSystemDefense == null) return;
            var x = '';

            // Get active policies
            xxSystemDefenceLinkedPolicy = {};
            for (var i in xxSystemDefense['AMT_NetworkPortSystemDefensePolicy'].responses) {
                var link = xxSystemDefense['AMT_NetworkPortSystemDefensePolicy'].responses[i];
                var a = +getItem(link['Antecedent']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'DeviceID')['Value'].substring(27);
                var b = link['Dependent']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
                var p = getItem(xxSystemDefense['AMT_SystemDefensePolicy'].responses, 'InstanceID', b);
                xxSystemDefenceLinkedPolicy[a] = p;
            }

            // Global System Defense settings
            x += TableStart();
            var policyname = ('<i>' + "None" + '</i>');
            if (xxSystemDefenceLinkedPolicy[0]) { policyname = xxSystemDefenceLinkedPolicy[0]['PolicyName']; }
            x += TableEntry("Default Wired Policy", addLink(policyname, 'changeDefaultPolicy(0)'));
            /*
            policyname = ('<i>' + "None" + '</i>');
            if (xxSystemDefenceLinkedPolicy[1]) { policyname = xxSystemDefenceLinkedPolicy[1]['PolicyName']; }
            x += TableEntry("Default Wireless Policy", addLink(policyname, 'changeDefaultPolicy(1)'));
            */

            // Filter Statistics
            for (var i = 0; i < 2; i++) {
                var f = xxFilterStatistics[i];
                for (var j in f) {
                    var c = f[j];
                    if (c == 1) c += " packet"; else c += " packets";
                    var jn = ((i==0)?"Wired ":"Wireless ") + j;
                    x += TableEntry(jn, c);
                }
            }
            x += TableEnd();
            x += '<br>';

            x += TableStart2();
            x += '<tr><td class=r1 style=padding-left:15px;border:0><br>' + "Manage Intel&reg; AMT system defense policies." + '<br><br>';
            if (xxSystemDefense['AMT_SystemDefensePolicy'].responses.length == 0) {
                x += '<div style=padding-left:15px><i>' + "No system defense policies found." + '</i></div><br>';
            } else {
                for (var i in xxSystemDefense['AMT_SystemDefensePolicy'].responses) {
                    var policy = xxSystemDefense['AMT_SystemDefensePolicy'].responses[i];
                    var desc = '';
                    if (policy['FilterCreationHandles']) {
                        policy['FilterCreationHandles'] = MakeToArray(policy['FilterCreationHandles']);
                        var c = policy['FilterCreationHandles'].length;
                        desc = ', ' + c + ' filter' + (c > 1?'s':'');
                    }
                    x += '<div class=itemBar onclick=showPolicyDetails(' + i + ')><div style=padding-top:3px><b>' + EscapeHtml(policy['PolicyName']) + '</b>' + desc + '</div></div>';
                }
            }

            x += '<tr><td class=r1 style=padding-left:15px><br>' + "Manage Intel&reg; AMT system defense filters." + '<br><br>';
            if (xxSystemDefense['AMT_Hdr8021Filter'].responses.length == 0 && xxSystemDefense['AMT_IPHeadersFilter'].responses.length == 0) {
                x += '<div style=padding-left:15px><i>' + "No system defense filters found." + '</i></div><br>';
            } else {
                for (var i in xxSystemDefense['AMT_Hdr8021Filter'].responses) {
                    var filter = xxSystemDefense['AMT_Hdr8021Filter'].responses[i];
                    var desc = xxSystemDefenceFilterEthernetTypes[filter['HdrProtocolID8021']];
                    if (!desc) desc = "All Ethernet Protocol " + filter['HdrProtocolID8021'];
                    desc += ', ' + xxSystemDefenceFilterDesc[filter['FilterProfile']];
                    if (filter['FilterProfile'] == 2) { desc += " at " + filter['FilterProfileData'] + " packet / sec"; }
                    if (filter['ActionEventOnMatch'] == true) desc += ", Event on match";
                    x += '<div class=itemBar onclick=showFilterDetails(0,' + i + ')><div style=padding-top:3px><b>' + (filter['FilterDirection'] == 0 ? '&#8592; ' : '&#8594; ') + EscapeHtml(filter['Name']) + '</b>, ' + desc + '</div></div>';
                }
                for (var i in xxSystemDefense['AMT_IPHeadersFilter'].responses) {
                    var filter = xxSystemDefense['AMT_IPHeadersFilter'].responses[i];
                    var desc = xxSystemDefenceFilterIPTypes[filter['HdrIPVersion']];
                    if (!desc) desc = "All Ethernet Protocol " + filter['HdrIPVersion'];
                    desc += ', ' + xxSystemDefenceFilterDesc[filter['FilterProfile']];
                    if (filter['FilterProfile'] == 2) { desc += " at " + filter['FilterProfileData'] + " packet / sec"; }
                    if (filter['ActionEventOnMatch'] == true) desc += ", Event on match";
                    var filtercount = 0;
                    for (var j in xxSystemDefenceFilters) { if (filter[j]) filtercount++; }
                    if (filtercount > 0) desc += ', ' + filtercount + ' filter' + (filtercount>1?'s':'');
                    x += '<div class=itemBar onclick=showFilterDetails(1,' + i + ')><div style=padding-top:3px><b>' + (filter['FilterDirection'] == 0 ? '&#8592; ' : '&#8594; ') + EscapeHtml(filter['Name']) + '</b>, ' + desc + '</div></div>';
                }
            }
            x += '<br><td class=r1>' + TableEnd(AddRefreshButton('PullSystemDefense()') + /*AddButton("Update Stats", 'UpdateDefenseStats()') +*/ AddButton("Add Filter...", 'AddDefenseFilter()') + AddButton("Add Policy...", 'AddDefensePolicy()'));

            QH('id_TableSystemDefense', x);

            if (xxFilterStatisticsTimer == null) {
                xxFilterStatisticsTimerActive = false;
                if (!urlvars['norefresh']) {
                    UpdateDefenseStats();
                    xxFilterStatisticsTimer = setInterval(UpdateDefenseStats, 5000);
                }
            }
        }

        function StopDefenseStatsTimer() {
            if (xxFilterStatisticsTimer != null) { clearInterval(xxFilterStatisticsTimer); xxFilterStatisticsTimer = null; }
            xxFilterStatisticsTimerActive = false;
        }

        function UpdateDefenseStats(n) {
            if (!n && xxFilterStatisticsTimerActive == true) { return; }
            xxFilterStatisticsTimerActive = true;
            var network = n?n:0;
            if (xxSystemDefenceLinkedPolicy[network]) {
                var eref = '<a:Address></a:Address><a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPort</w:ResourceURI><w:SelectorSet><w:Selector Name="DeviceID">Intel(r) AMT Ethernet Port ' + network + '</w:Selector></w:SelectorSet></a:ReferenceParameters>';
                amtstack.AMT_SystemDefensePolicy_UpdateStatistics(eref, false, UpdateDefenseStats2, network, 0, { 'InstanceID': xxSystemDefenceLinkedPolicy[network]['InstanceID'] });
            } else {
                // No active policy, stop the timer
                xxFilterStatistics[network] = {};
                StopDefenseStatsTimer();
            }
        }

        function UpdateDefenseStats2(stack, name, responses, status, network) {
            if (status == 200) {
                amtstack.Enum('AMT_ActiveFilterStatistics', UpdateDefenseStats3, network);
            } else {
                StopDefenseStatsTimer();
            }
        }

        function UpdateDefenseStats3(stack, name, responses, status, network) {
            var count = 0;
            if (status == 200) {
                xxFilterStatistics[network] = {};
                for (var i in responses) {
                    var readcount = responses[i]['ReadCount'];
                    // var matched = responses[i]['FilterMatched'];
                    var name = getItem(responses[i]['Dependent']['ReferenceParameters']['SelectorSet']['Selector'][1]['Value']['EndpointReference']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'Name')['Value'];
                    xxFilterStatistics[network][name] = readcount;
                    count++;
                }
                updateSystemDefense();
            }
            xxFilterStatisticsTimerActive = false;
            // If there is no statistics, stop the timer
            if (count == 0) { StopDefenseStatsTimer(); } // TODO: Change this to allow for wireless
        }

        function changeDefaultPolicy(network) {
            if (xxdialogMode) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><select id=policySelection style=float:right;width:266px><option value=-1>' + "None";
            for (var i in xxSystemDefense['AMT_SystemDefensePolicy'].responses) { x += '<option value=' + i + ((xxSystemDefenceLinkedPolicy[network] && xxSystemDefense['AMT_SystemDefensePolicy'].responses[i]['InstanceID'] == xxSystemDefenceLinkedPolicy[network]['InstanceID']) ? ' selected' : '') + '>' + xxSystemDefense['AMT_SystemDefensePolicy'].responses[i]['PolicyName']; }
            x += '</select><div style=padding-top:4px>' + "Default Policy" + '</div></div>';
            setDialogMode(11, "Default System Defense Policy", 3, changeDefaultPolicyOk, x, network);
        }

        function changeDefaultPolicyOk(button, network) {
            var i = Q('policySelection').value;
            var oldpolicy = xxSystemDefenceLinkedPolicy[network];
            if (oldpolicy) { amtstack.Delete('AMT_NetworkPortSystemDefensePolicy', '<w:SelectorSet><w:Selector Name="Antecedent"><a:EndpointReference xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPort</w:ResourceURI><w:SelectorSet><w:Selector Name="CreationClassName">CIM_EthernetPort</w:Selector><w:Selector Name="DeviceID">Intel(r) AMT Ethernet Port ' + network + '</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference></w:Selector><w:Selector Name="Dependent"><a:EndpointReference xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://intel.com/wbem/wscim/1/amt-schema/1/AMT_SystemDefensePolicy</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + oldpolicy['InstanceID'] + '</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference></w:Selector></w:SelectorSet>', ((i == -1) ? PullSystemDefense : function () { })); }

            if (i >= 0) {
                var policy = xxSystemDefense['AMT_SystemDefensePolicy'].responses[i];
                var eref = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_EthernetPort</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="DeviceID">' + "Intel(r) AMT Ethernet Port" + ' ' + network + '</Selector></SelectorSet></ReferenceParameters>';
                var pref = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_SystemDefensePolicy</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">' + policy['InstanceID'] + '</Selector></SelectorSet></ReferenceParameters>';
                amtstack.Create('AMT_NetworkPortSystemDefensePolicy', { 'Antecedent': eref, 'Dependent': pref }, changeDefaultPolicyOk2);
            }
        }

        function changeDefaultPolicyOk2(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Default System Defense Policy", "Unable to set policy, error " + status);
            } else {
                PullSystemDefense();
            }
        }

        function AddDefenseFilter() {
            if (xxdialogMode) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><input id=filtername style=float:right;width:260px maxlength=16 onkeyup=AddDefenseFilterUpdate()><div style=padding-top:4px>' + "Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=filtertype style=float:right;width:266px onchange=AddDefenseFilterUpdate()><option value=0>' + "Ethernet IP Packet Filter" + '<option value=1>' + "Ethernet ARP Packet Filter" + '<option value=2>' + "IPv4 Packet Filter" + '<option value=3>' + "IPv6 Packet Filter" + '</select><div style=padding-top:4px>' + "Type" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px id=ipfilterdiv><input id=ipfilter style=float:right;width:260px placeholder=\"' + "Optional Rules" + '\" onkeyup=AddDefenseFilterUpdate()><div style=padding-top:4px>' + "Matching Rules" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=filterdir style=float:right;width:266px onchange=AddDefenseFilterUpdate()><option value=0>' + "Outbound / Transmit" + '<option value=1>' + "Inbound / Receive" + '</select><div style=padding-top:4px>' + "Direction" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=filterprofile style=float:right;width:266px onchange=AddDefenseFilterUpdate()><option value=0>' + "Allow, Count" + '<option value=1>' + "Drop, Count" + '<option value=2>' + "Rate Limit" + '<option value=3>' + "Allow" + '<option value=4>' + "Drop" + '</select><div style=padding-top:4px>' + "Action" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px id=filterdatadiv><input id=filterdata style=float:right;width:260px maxlength=8 onkeyup=AddDefenseFilterUpdate()><div style=padding-top:4px>' + "Packets / second" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=filteraction style=float:right;width:266px onchange=AddDefenseFilterUpdate()><option value=false>' + "Do Nothing" + '<option value=1>' + "Event on match" + '</select><div style=padding-top:4px>' + "Event Log" + '</div></div>';
            setDialogMode(11, "Add System Defense Filter", 3, AddDefenseFilterOk, x);
            AddDefenseFilterUpdate();
        }

        function AddDefenseFilterOk() {
            if (Q('filtertype').value <= 1) {
                // Add Ethernet IP or ARP filter
                var protocol = (Q('filtertype').value == 0) ? 2048 : 2054; // IP : ARP
                var filter = { 'InstanceID ': 0, 'Name': Q('filtername').value, 'CreationClassName': 0, 'SystemName': 0, 'SystemCreationClassName': 0, 'HdrProtocolID8021': protocol, 'FilterProfile': Q('filterprofile').value, 'FilterDirection': Q('filterdir').value, 'ActionEventOnMatch': Q('filteraction').value };
                if (Q('filterprofile').value == 2) filter['FilterProfileData'] = Q('filterdata').value;
                amtstack.Create('AMT_Hdr8021Filter', filter, AddDefenseFilterOk2);
            } else {
                // Add IPv4 or IPv6 Filter
                var protocol = (Q('filtertype').value == 2) ? 4 : 6; // IPv4 : IPv6
                var filter = { 'InstanceID ': 0, 'Name': Q('filtername').value, 'CreationClassName': 0, 'SystemName': 0, 'SystemCreationClassName': 0, 'HdrIPVersion': protocol, 'FilterProfile': Q('filterprofile').value, 'FilterDirection': Q('filterdir').value, 'ActionEventOnMatch': Q('filteraction').value };

                // Parse the filter string
                // https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/default.htm?turl=HTMLDocuments%2FWS-Management_Class_Reference%2FAMT_Hdr8021Filter.htm
                var filterstrs = Q('ipfilter').value.split(',');
                for (var i in filterstrs) {
                    var xx = filterstrs[i].indexOf('=');
                    var n = filterstrs[i].substring(0, xx);
                    var v = filterstrs[i].substring(xx + 1);
                    var t = xxSystemDefenceFilters[n];
                    if (!t) { n = "Hdr" + n; t = xxSystemDefenceFilters[n]; }
                    if (t) {
                        // TODO: Parse v (the value) based on the type t.
                        if (t == 2 && protocol == 4) {
                            // IPv4 address
                            var ipsplit = v.split('.');
                            if (ipsplit.length == 4) {
                                //filter[n] = btoa(String.fromCharCode(parseInt(ipsplit[0]), parseInt(ipsplit[1]), parseInt(ipsplit[2]), parseInt(ipsplit[3])));
                                //filter[n] = [ parseInt(ipsplit[0]), parseInt(ipsplit[1]), parseInt(ipsplit[2]), parseInt(ipsplit[3]) ];
                                filter[n] = rstr2hex(String.fromCharCode(parseInt(ipsplit[0]), parseInt(ipsplit[1]), parseInt(ipsplit[2]), parseInt(ipsplit[3])));
                            }
                        } else {
                            // Other values
                            filter[n] = v;
                        }
                    }
                }

                if (Q('filterprofile').value == 2) filter['FilterProfileData'] = Q('filterdata').value;
                amtstack.Create('AMT_IPHeadersFilter', filter, AddDefenseFilterOk2);
            }
        }

        function AddDefenseFilterUpdate() {
            var ok = Q('filtername').value.length > 0;
            if (ok && Q('filterprofile').value == 2) { var i = parseInt(Q('filterdata').value); ok = (i > 0 && i < 0xFFFFFFFF); }
            QE('idx_dlgOkButton', ok);
            QV('filterdatadiv', Q('filterprofile').value == 2);
            QV('ipfilterdiv', Q('filtertype').value >= 2);
        }

        function AddDefenseFilterOk2(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Add System Defense Filter", "Unable to add filter, error #" + status);
            } else {
                PullSystemDefense();
            }
        }

        function showFilterDetails(t, i) {
            if (xxdialogMode) return;
            var desc, filter, type, tn;
            if (t == 0) {
                tn = 'AMT_Hdr8021Filter';
                type = "Ethernet Traffic";
                filter = xxSystemDefense[tn].responses[i];
                desc = xxSystemDefenceFilterEthernetTypes[filter['HdrProtocolID8021']];
                if (!desc) desc = "All Ethernet Protocol " + filter['HdrProtocolID8021'];
            } else {
                tn = 'AMT_IPHeadersFilter';
                type = "IP Traffic";
                filter = xxSystemDefense[tn].responses[i];
                desc = xxSystemDefenceFilterIPTypes[filter['HdrIPVersion']];
                if (!desc) desc = "All IP Protocol " + filter['HdrIPVersion'];
            }
            var x = '';
            x += addHtmlValue("Name", EscapeHtml(filter['Name']));
            x += addHtmlValue("Type", type);
            x += addHtmlValue("Matching Traffic", desc);
            x += addHtmlValue("Direction", filter['FilterDirection'] == 0 ? 'Outbound / Transmit' : 'Inbound / Receive');
            if (t == 1) {
                for (var j in xxSystemDefenceFilters) {
                    if (filter[j]) {
                        var n = j, v = filter[j], t = xxSystemDefenceFilters[j];
                        if (t == 2 && v.length == 4) { v = hex2rstr(v); v = v.charCodeAt(0) + '.' + v.charCodeAt(1) + '.' + v.charCodeAt(2) + '.' + v.charCodeAt(3); }
                        if (n.startsWith('Hdr')) n = n.substring(3);
                        x += addHtmlValue("Filter " + n, v);
                    }
                }
            }
            x += addHtmlValue("Event on match", (filter['ActionEventOnMatch'] == true) ? 'Yes' : 'No');
            setDialogMode(11, "Ethernet Filter #" + filter['InstanceID'], 5, showFilterDetailsOk, x, [tn, filter]);
        }

        function showFilterDetailsOk(b, tag) {
            if (b == 2) { amtstack.Delete(tag[0], tag[1], deleteDefenseFilter); }
        }

        function deleteDefenseFilter(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Remove Filter", "Unable to remove filter, make sure it's not in use.");
            } else {
                PullSystemDefense();
            }
        }

        var xxAddDefensePolicyFilters;
        function AddDefensePolicy() {
            if (xxdialogMode) return;
            xxAddDefensePolicyFilters = [];
            var x = '';
            x += '<div style=height:26px;margin-top:4px><input id=policyname title="<policy name>:<policy precedence number>" style=float:right;width:260px maxlength=16 onkeyup=AddDefensePolicyUpdate()><div style=padding-top:4px>' + "Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><select id=policytx title="' + "Default action to take for outbound traffic" + '" style=float:right;width:133px><option value=0>Allow<option value=1>' + "Drop" + '<option value=2>' + "Allow,Count" +'<option value=3>' + "Drop,Count" + '<option value=4>' + "Allow,Count,Event" + '<option value=5>' + "Drop,Count,Event" + '</select><select id=policyrx style=float:right;width:133px title="' + "Default action to take for inbound traffic" + '"><option value=0>' + "Allow" + '<option value=1>' + "Drop" + '<option value=2>' + "Allow,Count" + '<option value=3>' + "Drop,Count" + '<option value=4>' + "Allow,Count,Event" + '<option value=5>' + "Drop,Count,Event" + '</select><div style=padding-top:4px>' + "Default TX / RX" + '</div></div>';
            x += '<div id=policyFilters></div>';
            if (xxSystemDefense['AMT_Hdr8021Filter'].responses.length > 0 || xxSystemDefense['AMT_IPHeadersFilter'].responses.length > 0) {
                x += '<div style=height:26px;margin-top:4px><div style=float:right><select id=xfilter style=width:186px>';
                for (var i in xxSystemDefense['AMT_Hdr8021Filter'].responses) {
                    var filter = xxSystemDefense['AMT_Hdr8021Filter'].responses[i];
                    x += '<option value=' + filter['InstanceID'] + '>' + filter['Name'];
                }
                for (var i in xxSystemDefense['AMT_IPHeadersFilter'].responses) {
                    var filter = xxSystemDefense['AMT_IPHeadersFilter'].responses[i];
                    x += '<option value=' + filter['InstanceID'] + '>' + filter['Name'];
                }
                x += '</select><input id=addFilterButton type=button value=Add style=width:80px onclick=addFilterButton()></div><div style=padding-top:4px>' + "Add Filter" + '</div></div>';
            }
            setDialogMode(11, "Add System Defense Policy", 3, AddDefensePolicyOk, x);
            AddDefensePolicyUpdate();
        }

        function addFilterButton() {
            if (xxAddDefensePolicyFilters.indexOf(Q('xfilter').value) >= 0) return;
            xxAddDefensePolicyFilters.push(Q('xfilter').value);
            AddDefensePolicyUpdate();
        }

        function removeFilterButton(h) {
            xxAddDefensePolicyFilters.splice(h, 1);
            AddDefensePolicyUpdate();
        }

        function AddDefensePolicyUpdate() {
            var ok = Q('policyname').value.split(':')[0].length > 0;
            QE('idx_dlgOkButton', ok);
            if (xxAddDefensePolicyFilters.length == 0) {
                QH('policyFilters', '<br><i>' + "This policy contains no filters." + '</i><br><br>');
            } else {
                var x = '';
                for (var i in xxAddDefensePolicyFilters) {
                    x += '<div class=itemBar style=margin-right:0><div style=float:right>' + AddButton2("Remove", 'removeFilterButton(' + i + ')') + '</div><div style=padding-top:3px;max-width:260px;overflow:hidden><b>' + GetFilterById(xxAddDefensePolicyFilters[i])['Name'] + '</b></div></div>';
                }
                QH('policyFilters', x);
            }
        }

        // TODO: Once loaded, we could make a table of "handle -> filter" where both filter types are mixed-in. Could make things simpler/smaller?
        // We would only have one table to loop instead of two at a few places. This function would be removed completely.
        function GetFilterById(h) {
            for (var i in xxSystemDefense['AMT_Hdr8021Filter'].responses) { var filter = xxSystemDefense['AMT_Hdr8021Filter'].responses[i]; if (filter['InstanceID'] == h) return filter; }
            for (var i in xxSystemDefense['AMT_IPHeadersFilter'].responses) { var filter = xxSystemDefense['AMT_IPHeadersFilter'].responses[i]; if (filter['InstanceID'] == h) return filter; }
        }

        function AddDefensePolicyOk() {
            var tx = Q('policytx').value;
            var rx = Q('policyrx').value;
            var pri = 0;
            var n = Q('policyname').value.split(':');
            if (n.length == 2) pri = parseInt(n[1]);
            var filter = { 'InstanceID ': 0, 'PolicyName': n[0], 'PolicyPrecedence': pri, 'TxDefaultCount': (tx > 1), 'TxDefaultDrop': (tx % 2 == 1), 'TxDefaultMatchEvent': (tx > 3), 'RxDefaultCount': (rx > 1), 'RxDefaultDrop': (rx % 2 == 1), 'RxDefaultMatchEvent': (rx > 3) };
            if (xxAddDefensePolicyFilters.length > 0) filter['FilterCreationHandles'] = xxAddDefensePolicyFilters;
            amtstack.Create('AMT_SystemDefensePolicy', filter, AddDefensePolicyOk2);
        }

        function AddDefensePolicyOk2(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Add System Defense Policy", "Unable to add policy, error #" + status);
            } else {
                PullSystemDefense();
            }
        }

        function showPolicyDetails(i) {
            if (xxdialogMode) return;
            var policy = xxSystemDefense['AMT_SystemDefensePolicy'].responses[i];
            var x = '';
            x += addHtmlValue("Name", EscapeHtml(policy['PolicyName']));
            if (policy['PolicyPrecedence'] != 0) x += addHtmlValue("Precedence", policy['PolicyPrecedence']);

            var action = (policy['TxDefaultDrop'] == true) ? "Drop" : "Allow";
            if (policy['TxDefaultCount'] == true) action += ", Count";
            if (policy['TxDefaultMatchEvent'] == true) action += ", Event";
            x += addHtmlValue("Default TX Action", action);

            action = (policy['RxDefaultDrop'] == true) ? 'Drop' : 'Allow';
            if (policy['RxDefaultCount'] == true) action += ', Count';
            if (policy['RxDefaultMatchEvent'] == true) action += ', Event';
            x += addHtmlValue("Default RX Action", action);

            if (policy['FilterCreationHandles']) { for (var i in policy['FilterCreationHandles']) { x += addHtmlValue("Filter #" + (+i + 1), GetFilterById(policy['FilterCreationHandles'][i])['Name']); } }

            setDialogMode(11, format("Policy #", policy['InstanceID'].substring(20)), 5, showPolicyDetailsOk, x, policy);
        }

        function showPolicyDetailsOk(b, tag) {
            if (b == 2) { amtstack.Delete('AMT_SystemDefensePolicy', tag, deleteDefensePolicy); }
        }

        function deleteDefensePolicy(stack, name, responses, status) {
            if (status != 200) {
                messagebox("Remove Policy", "Unable to remove policy, make sure it's not in use.");
            } else {
                PullSystemDefense();
            }
        }

// ###END###{SystemDefense}

// ###BEGIN###{NetworkSettings}
// ###BEGIN###{Wireless}

        //
        // WIRELESS SETTINGS PANEL
        //

        var xxWireless;
        function PullWireless() {
            amtFirstPull |= 2;
            try { if (amtwirelessif == -1) return; } catch (e) { } // If the wireless adapter has no MAC, don't show this.
            // ###BEGIN###{!NetAuth}
            amtstack.BatchEnum('', ['*CIM_WiFiPortCapabilities', '*CIM_WiFiPort', '*CIM_WiFiEndpoint', 'CIM_WiFiEndpointSettings', '*AMT_WiFiPortConfigurationService'], processWireless);
            // ###END###{!NetAuth}
            // ###BEGIN###{NetAuth}
            amtstack.BatchEnum('', ['*CIM_WiFiPortCapabilities', '*CIM_WiFiPort', '*CIM_WiFiEndpoint', 'CIM_WiFiEndpointSettings', '*AMT_WiFiPortConfigurationService', 'CIM_IEEE8021xSettings'], processWireless);
            // ###END###{NetAuth}
        }

        function wifiRefresh() { if (!xxdialogMode) PullWireless(); }

        var xxWifiState = { 3: "Disabled", 32768: "Enabled in S0", 32769: "Enabled in S0, Sx/AC" };
        var xxRadioState = 	{ 2: "On, Connected", 3: "Off", 6: "On, Disconnected" };
        var xxWifiAuthenticationMethod = { 1: "Other", 2: "Open", 3: "Shared Key", 4: "WPA PSK", 5: "WPA IEEE 802.1x", 6: "WPA2 PSK", 7: "WPA2 IEEE 802.1x", 32768: "WPA3 SAE IEEE 802.1x", 32769: "WPA3 OWE IEEE 802.1x" };
        var xxWifiEncryptionMethod = { 1: "Other", 2: "WEP", 3: "TKIP-RC4", 4: "CCMP-AES", 5: "None" }; // For 2 & 5, AuthenticationMethod must be 2 or 3. For 3 & 4 AuthenticationMethod must be 4,5,6 or 7

        function processWireless(stack, name, responses, status) {
            if (status == 200) { xxWireless = responses; } else { xxWireless = undefined; }
            updateSystemStatus();
            showWirelessInfo();
        }

        function showWirelessInfo() {
            if (!xxWireless) return;
            var i, j, s = '', sc, x = '<br><h2>' + "Wireless Profiles" + '</h2>';
            if (!(xxWireless['CIM_WiFiPortCapabilities'].response)) return;

            // Show WIFI profiles sorted by priority
            x += TableStart2();
            x += '<tr><td class=r2 style=padding-left:15px><br>' + "Wireless profiles that Intel&reg; AMT will use for network connectivity." + '<br><br>';
            s = 0;
            for(i = 0; i < 256; i++) {
                for (j in xxWireless['CIM_WiFiEndpointSettings'].responses) {
                    sc = xxWireless['CIM_WiFiEndpointSettings'].responses[j];
                    if (sc['AuthenticationMethod'] == 1) continue; // Skip "Endpoint User Settings"
                    if (sc['Priority'] == i) {
                        var details = '';
                        // ###BEGIN###{NetAuth}
                        var netAuthProfile = null, netAuthProtocols = ['EAP-TLS', 'EAP-TTLS/MSCHAPv2', 'PEAPv0/EAP-MSCHAPv2', 'PEAPv1/EAP-GTC', 'EAP-FAST/MSCHAPv2', 'EAP-FAST/GTC', 'EAP-MD5', 'EAP-PSK', 'EAP-SIM', 'EAP-AKA', 'EAP-FAST/TLS'];
                        if (xxWireless['CIM_IEEE8021xSettings'].responses) {
                            for (var k in xxWireless['CIM_IEEE8021xSettings'].responses) {
                                if (xxWireless['CIM_IEEE8021xSettings'].responses[k]['ElementName'] == sc['ElementName']) { netAuthProfile = xxWireless['CIM_IEEE8021xSettings'].responses[k]; }
                            }
                        }
                        if (netAuthProfile) { details = ', ' + netAuthProtocols[netAuthProfile['AuthenticationProtocol']]; }
                        // ###END###{NetAuth}
                        x += '<div class=itemBar onclick=showWifiDetails(' + j + ')><div style=float:right>' + EscapeHtml(sc['SSID']) + ', ' + xxWifiAuthenticationMethod[sc['AuthenticationMethod']] + ', ' + xxWifiEncryptionMethod[sc['EncryptionMethod']] + details + ' &nbsp; ';
                        if (xxAccountAdminName) x += AddButton2("Remove", 'wifiRemoveButton(\"' + j + '\")');
                        x += '</div><div style=padding-top:3px><b>' + EscapeHtml(sc['ElementName']) + '</b></div></div>';
                        s++;
                    }
                }
            }
            if (s == 0) x += '<i>' + "No Wireless Profiles Present" + '</i><br>';

            // End of table
            x += '<br><td class=r2>';
            if (xxAccountAdminName) x += TableEnd(AddButton("New Profile", 'showWifiNewProfile()')); else x += TableEnd('');
            QH('id_TableWifi2', x + '<br>');
        }
        
        function showWifiStateDlg() {
            if (xxdialogMode) return;
            var s = '';
            for (var i in xxWifiState) { s += '<label><input type=radio name=d11 id=wl' + i + ' value=' + i + ' ' + ((xxWireless['CIM_WiFiPort'].response['EnabledState'] == i)?'checked':'') + '>' + xxWifiState[i] + '</label><br>'; }
            setDialogMode(11, "Wireless State", 3, wifiStateDlg, s);
        }

        function wifiStateDlg() { amtstack.CIM_WiFiPort_RequestStateChange( document.querySelector('input[name=d11]:checked').value, null, function() { amtstack.Get('CIM_WiFiPort', function(stack, name, response, status) { if (status == 200) { xxWireless['CIM_WiFiPort'].response = response.Body; showWirelessInfo(); } } ); } ); }

        function showWifiSyncDlg() {
            if (xxdialogMode) return;
            var s = '';
            s += '<label><input type=radio name=d11 id=wl0 value=0 ' + ((xxWireless['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 0) ? 'checked' : '') + '>' + "Disabled" + '</label><br>';
            s += '<label><input type=radio name=d11 id=wl0 value=1 ' + ((xxWireless['AMT_WiFiPortConfigurationService'].response['localProfileSynchronizationEnabled'] == 1) ? 'checked' : '') + '>' + "Enabled" + '</label><br>';
            setDialogMode(11, "Local Profile Sync", 3, showWifiSyncDlgEx, s);
        }

        function showWifiSyncDlgEx() {
            var k = Clone(xxWireless['AMT_WiFiPortConfigurationService'].response);
            k['localProfileSynchronizationEnabled'] = document.querySelector('input[name=d11]:checked').value;
            amtstack.Put('AMT_WiFiPortConfigurationService', k, function () { amtstack.Get('AMT_WiFiPortConfigurationService', function (stack, name, response, status) { if (status == 200) { xxWireless['AMT_WiFiPortConfigurationService'].response = response.Body; showWirelessInfo(); } }); });
        }
        
        function showUefiWifiCoExDlg() {
            if (xxdialogMode) return;
            var s = '';
            s += '<label><input type=radio name=d12 value=0 ' + ((xxWireless['AMT_WiFiPortConfigurationService'].response['UEFIWiFiProfileShareEnabled'] == false)?'checked':'') + '>Disabled</label><br>'; 
            s += '<label><input type=radio name=d12 value=1 ' + ((xxWireless['AMT_WiFiPortConfigurationService'].response['UEFIWiFiProfileShareEnabled'] == true)?'checked':'') + '>Enabled</label><br>'; 
            setDialogMode(11, "UEFI Wifi CoEx Profile Sharing", 3, UefiWifiCoExDlg, s);
        }
        
        function UefiWifiCoExDlg() {
            var wifiportcfgsvc = Clone(xxWireless['AMT_WiFiPortConfigurationService'].response);
            wifiportcfgsvc["UEFIWiFiProfileShareEnabled"]=document.querySelector('input[name=d12]:checked').value;
            amtstack.Put('AMT_WiFiPortConfigurationService', wifiportcfgsvc, function(stack, name, responses, status) {if (status == 200) {PullWireless()}})
        }

        function showWifiDetails(h) {
            if (xxdialogMode) return;
            var i, sc = xxWireless['CIM_WiFiEndpointSettings'].responses[h], x = '<div style=text-align:left>';
            x += addHtmlValue("Profile Name", EscapeHtml(sc['ElementName']));
            x += addHtmlValue("SSID", EscapeHtml(sc['SSID']));
            x += addHtmlValue("Authentication", xxWifiAuthenticationMethod[sc['AuthenticationMethod']]);
            x += addHtmlValue("Encryption", xxWifiEncryptionMethod[sc['EncryptionMethod']]);
            x += addHtmlValue("Priority", sc['Priority']);
            // ###BEGIN###{NetAuth}
            var netAuthProfile = null, netAuthProtocols = ['EAP-TLS', 'EAP-TTLS/MSCHAPv2', 'PEAPv0/EAP-MSCHAPv2', 'PEAPv1/EAP-GTC', 'EAP-FAST/MSCHAPv2', 'EAP-FAST/GTC', 'EAP-MD5', 'EAP-PSK', 'EAP-SIM', 'EAP-AKA', 'EAP-FAST/TLS'];
            if (xxWireless['CIM_IEEE8021xSettings'].responses) {
                for (var k in xxWireless['CIM_IEEE8021xSettings'].responses) {
                    if (xxWireless['CIM_IEEE8021xSettings'].responses[k]['ElementName'] == sc['ElementName']) { netAuthProfile = xxWireless['CIM_IEEE8021xSettings'].responses[k]; }
                }
            }
            if (netAuthProfile) {
                x += '<div style="width:100%;border-bottom:1px solid #000;margin-bottom:5px;margin-top:5px">802.11x</div>'
                x += addHtmlValue("Authentication", netAuthProtocols[netAuthProfile['AuthenticationProtocol']]);
                if (netAuthProfile['Domain']) { x += addHtmlValue("Domain", EscapeHtml(netAuthProfile['Domain'])); }
                if (netAuthProfile['Username']) { x += addHtmlValue("Username", EscapeHtml(netAuthProfile['Username'])); }
            }
            // ###END###{NetAuth}
            x += '</div>';
            messagebox("Wireless Profile", x);
        }

        function wifiRemoveButton(h) {
            if (xxdialogMode) return;
            var sc = xxWireless['CIM_WiFiEndpointSettings'].responses[h];
            QH('id_dialogMessage', format("Remove wireless profile \"{0}\"?", sc['ElementName']));
            setDialogMode(1, "Wireless Profile", 3, function () { removeWifiButtonEx(h) });
        }

        function removeWifiButtonEx(h) {
            var sc = xxWireless['CIM_WiFiEndpointSettings'].responses[h];
            amtstack.Delete('CIM_WiFiEndpointSettings', { InstanceID: sc['InstanceID'] }, removeWifiEntryResponse, 0, 1);
        }

        function removeWifiEntryResponse(stack, name, response, status, tag) {
            if (methodcheck(response)) return;
            // ###BEGIN###{!NetAuth}
            amtstack.BatchEnum('', ['CIM_WiFiEndpointSettings'], function (stack, name, responses, status) {
                if (status == 200) {
                    xxWireless['CIM_WiFiEndpointSettings'].responses = responses['CIM_WiFiEndpointSettings'].responses;
                    showWirelessInfo();
                }
            });
            // ###END###{!NetAuth}
            // ###BEGIN###{NetAuth}
            amtstack.BatchEnum('', ['CIM_WiFiEndpointSettings', 'CIM_IEEE8021xSettings'], function (stack, name, responses, status) {
                if (status == 200) {
                    xxWireless['CIM_WiFiEndpointSettings'].responses = responses['CIM_WiFiEndpointSettings'].responses;
                    xxWireless['CIM_IEEE8021xSettings'].responses = responses['CIM_IEEE8021xSettings'].responses;
                    showWirelessInfo();
                }
            });
            // ###END###{NetAuth}
        }

        function showWifiNewProfile() {
            if (xxdialogMode) return;
            var x = '';
            for (i = 1; i < 256; i++) {
                var t = 1;
                for (j in xxWireless['CIM_WiFiEndpointSettings'].responses) { if (xxWireless['CIM_WiFiEndpointSettings'].responses[j]['Priority'] == i) t = 0; }
                if (t) { x += '<option value='+ i +'>'+ i; } // Option is a tag that is self closing.
            }
            QH('idx_d12pri', x);

            // ###BEGIN###{NetAuth}
            // Set certificates
            var clientcertoptions = '<option value=-1>' + EscapeHtml("None") + '</option>', servercertoptions = '<option value=-1>' + EscapeHtml("None") + '</option>';
            for (var i in xxCertificates) {
                if (xxCertificates[i].TrustedRootCertficate) {
                    servercertoptions += '<option value="' + i + '">' + EscapeHtml(xxCertificates[i].XSubject['CN']) + '</option>';
                } else if (xxCertificates[i].XPrivateKey) {
                    clientcertoptions += '<option value="' + i + '">' + EscapeHtml(xxCertificates[i].XSubject['CN']) + '</option>';
                }
            }
            QH('idx_d12clientcert', clientcertoptions);
            QH('idx_d12servercert', servercertoptions);
            // ###END###{NetAuth}

            var authOptions = '';
            // ###BEGIN###{NetAuth}
            authOptions += '<option value=32769>' + "WPA3 OWE IEEE 802.1x" + '</option>';
            authOptions += '<option value=32768>' + "WPA3 SAE IEEE 802.1x" + '</option>';
            authOptions += '<option value=7>' + "WPA2 IEEE 802.1x" + '</option>';
            authOptions += '<option value=5>' + "WPA IEEE 802.1x" + '</option>';
            // ###END###{NetAuth}
            authOptions += '<option value=6>' + "WPA2 PSK" + '</option>';
            authOptions += '<option value=4>' + "WPA PSK" + '</option>';
            QH('idx_d12auth', authOptions);

            idx_d12auth.value = 6;
            idx_d12enc.value = 4;
            idx_d12name.value = idx_d12ssid.value = idx_d12password1.value = idx_d12password2.value = '';

            setDialogMode(12, "Add Wireless Profile", 3, function () { addWifiProfile() });
            updateWifiDialog();
        }

        function addWifiProfile() {
            var sc, netAuthSettingsClientCert, netAuthSettingsServerCaCert;
            var v = {
                '__parameterType': 'instance',
                '__namespace': amtstack.CompleteName('CIM_WiFiEndpointSettings'),
                'ElementName': idx_d12name.value,
                'InstanceID': 'Intel(r) AMT:WiFi Endpoint Settings ' + idx_d12name.value,
                'AuthenticationMethod': idx_d12auth.value,
                'EncryptionMethod': idx_d12enc.value,
                'SSID': idx_d12ssid.value,
                'Priority': idx_d12pri.value
            };
            if ((idx_d12auth.value == 4) || (idx_d12auth.value == 6)) { v['PSKPassPhrase'] = idx_d12password1.value; }
            // ###BEGIN###{NetAuth}
            if ((idx_d12auth.value == 5) || (idx_d12auth.value == 7) || (idx_d12auth.value == 32768) || (idx_d12auth.value == 32769)) {
                sc = {
                    '__parameterType': 'instance',
                    '__namespace': amtstack.CompleteName('CIM_IEEE8021xSettings'),
                    'ElementName': '8021x-' + idx_d12name.value,
                    'InstanceID': '8021x-' + idx_d12name.value,
                    'ActiveInS0': (Q('idx_d12activeins0').value == 1),
                    'AuthenticationProtocol': Q('idx_d12protocol').value
                };
                if (Q('idx_d12roamingidentity').value != '') { sc['RoamingIdentity'] = Q('idx_d12roamingidentity').value; }
                if (Q('idx_d12servername').value != '') { sc['ServerCertificateName'] = Q('idx_d12servername').value; sc['ServerCertificateNameComparison'] = Q('idx_d12servernamecompare').value; }
                if (Q('idx_d12username').value != '') { sc['Username'] = Q('idx_d12username').value; }
                if (Q('idx_d12password').value != '') { sc['Password'] = Q('idx_d12password').value; }
                if (Q('idx_d12domain').value != '') { sc['Domain'] = Q('idx_d12domain').value; }
                if (Q('idx_d12protocol').value > 3) { sc['ProtectedAccessCredential'] = Q('idx_d12pac').value; sc['PACPassword'] = Q('idx_d12pacpassword').value; }
                if (parseInt(Q('idx_d12clientcert').value) >= 0) { netAuthSettingsClientCert = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyCertificate</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">' + xxCertificates[parseInt(Q('idx_d12clientcert').value)]['InstanceID'] + '</Selector></SelectorSet></ReferenceParameters>'; }
                if (parseInt(Q('idx_d12servercert').value) >= 0) { netAuthSettingsServerCaCert = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyCertificate</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">' + xxCertificates[parseInt(Q('idx_d12servercert').value)]['InstanceID'] + '</Selector></SelectorSet></ReferenceParameters>'; }
            }
            // ###END###{NetAuth}

            console.log('wifiepsettinginput', JSON.stringify(v, null, 2));
            console.log('netAuthProfile', JSON.stringify(sc, null, 2));
            console.log('netAuthSettingsClientCert', netAuthSettingsClientCert);
            console.log('netAuthSettingsServerCaCert', netAuthSettingsServerCaCert);

            amtstack.AMT_WiFiPortConfigurationService_AddWiFiSettings(
				{
				    '__parameterType': 'reference',
				    '__resourceUri': amtstack.CompleteName('CIM_WiFiEndpoint'),
				    'Name': 'WiFi Endpoint 0'
				}, v,
				sc, netAuthSettingsClientCert, netAuthSettingsServerCaCert, removeWifiEntryResponse
			);
        }

        function updateWifiDialog() {
            var r = true;
            var a = idx_d12auth.value;
            var e = idx_d12enc.value;
            //QV('id_d12e2', a < 4);
            //QV('id_d12e3', a > 3);
            //QV('id_d12e4', a > 3);
            //QV('id_d12e5', a < 4);
            if (a < 4 && (e == 3 || e == 4)) { idx_d12enc.value = 2; }
            if (a > 3 && (e == 2 || e == 5)) { idx_d12enc.value = 3; }
            if ((a == 32768) || (a == 32769)) { idx_d12enc.value = 4; }
            QV('idx_d12pass', (a == 4) || (a == 6));
            QV('idx_d12netauth', (a == 5) || (a == 7) || (a == 32768) || (a == 32769));

            // Check if there is already a profile with this name
            for (var j in xxWireless['CIM_WiFiEndpointSettings'].responses) { if (xxWireless['CIM_WiFiEndpointSettings'].responses[j]['ElementName'] == idx_d12name.value) { r = false; } }
            if ((idx_d12name.value.length == 0) && (idx_d12ssid.value.length == 0)) { r = false; }
            if (((a == 4) || (a == 6)) && ((idx_d12password1.value.length < 8) || (idx_d12password1.value.length > 63) || (idx_d12password1.value != idx_d12password2.value))) { r = false; }

            QE('idx_dlgOkButton', r);

            // ###BEGIN###{NetAuth}
            updateNetAuthDialog();
            // ###END###{NetAuth}
        }

        // ###BEGIN###{NetAuth}
        function updateNetAuth2Dialog() {
            QV('idx_d12servernamecomparediv', (Q('idx_d12servernamediv').value != ''));
            QV('idx_d12pacdiv', (Q('idx_d12protocol').value > 3));
            QV('idx_d12pacpassworddiv', (Q('idx_d12protocol').value > 3));
        }
        // ###END###{NetAuth}

// ###END###{Wireless}
// ###BEGIN###{NetAuth}

        //
        // 802.1x SETTINGS
        //

        function editNetAuthProfile() {
            if (xxdialogMode) return;

            // Set certificates
            var clientcertoptions = '<option value=-1>' + EscapeHtml("None") + '</option>', servercertoptions = '<option value=-1>' + EscapeHtml("None") + '</option>';
            for (var i in xxCertificates) {
                if (xxCertificates[i].TrustedRootCertficate) {
                    servercertoptions += '<option value="' + i + '">' + EscapeHtml(xxCertificates[i].XSubject['CN']) + '</option>';
                } else if (xxCertificates[i].XPrivateKey) {
                    clientcertoptions += '<option value="' + i + '">' + EscapeHtml(xxCertificates[i].XSubject['CN']) + '</option>';
                }
            }
            QH('idx_d27clientcert', clientcertoptions);
            QH('idx_d27servercert', servercertoptions);

            // Set profile
            var sc = amtsysstate['AMT_8021XProfile'].responses.Body;
            Q('idx_d27enabled').value = sc['Enabled'] ? 1 : 0;
            Q('idx_d27activeins0').value = (sc['ActiveInS0'] ? 1 : 0);
            Q('idx_d27pxetimeout').value = sc['PxeTimeout'];
            if (sc['Enabled']) {
                Q('idx_d27protocol').value = sc['AuthenticationProtocol'];
                Q('idx_d27roamingidentity').value = sc['RoamingIdentity'] ? sc['RoamingIdentity'] : '';
                Q('idx_d27servername').value = sc['ServerCertificateName'] ? sc['ServerCertificateName'] : '';
                Q('idx_d27servernamecompare').value = sc['ServerCertificateNameComparison'] ? sc['ServerCertificateNameComparison'] : 0;
                Q('idx_d27username').value = sc['Username'] ? sc['Username'] : '';
                Q('idx_d27password').value = sc['Password'] ? sc['Password'] : '';
                Q('idx_d27domain').value = sc['Domain'] ? sc['Domain'] : '';
                Q('idx_d27pac').value = sc['ProtectedAccessCredential'] ? sc['ProtectedAccessCredential'] : '';
                Q('idx_d27pacpassword').value = sc['PACPassword'] ? sc['PACPassword'] : '';
                var scInstanceId = -1, ccInstanceId = -1;
                if (sc['ServerCertificateIssuer']) { scInstanceId = sc['ServerCertificateIssuer']['ReferenceParameters']['SelectorSet']['Selector']['Value']; }
                if (sc['ClientCertificate']) { ccInstanceId = sc['ClientCertificate']['ReferenceParameters']['SelectorSet']['Selector']['Value']; }
                for (var i in xxCertificates) {
                    if (xxCertificates[i]['InstanceID'] == scInstanceId) { Q('idx_d27servercert').value = i; }
                    if (xxCertificates[i]['InstanceID'] == ccInstanceId) { Q('idx_d27clientcert').value = i; }
                }
            }
            setDialogMode(27, "802.1x Profile", 3, function () { setNetAuthProfile() });
            updateNetAuthDialog();
        }

        function updateNetAuthDialog() {
            QV('idx_d27protocoldiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27servernamediv', Q('idx_d27enabled').value == 1);
            QV('idx_d27servernamecomparediv', (Q('idx_d27enabled').value == 1) && (Q('idx_d27servername').value != ''));
            QV('idx_d27domaindiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27usernamediv', Q('idx_d27enabled').value == 1);
            QV('idx_d27passworddiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27roamingidentitydiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27pacdiv', (Q('idx_d27enabled').value == 1) && (Q('idx_d27protocol').value > 3));
            QV('idx_d27pacpassworddiv', (Q('idx_d27enabled').value == 1) && (Q('idx_d27protocol').value > 3));
            QV('idx_d27clientcertdiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27servercertdiv', Q('idx_d27enabled').value == 1);
            QV('idx_d27activeins0div', Q('idx_d27enabled').value == 1);
            QV('idx_d27pxetimeoutdiv', Q('idx_d27enabled').value == 1);
        }

        function setNetAuthProfile() {
            var sc = Clone(amtsysstate['AMT_8021XProfile'].responses.Body);
            sc['Enabled'] = (Q('idx_d27enabled').value == 1);
            if (sc['Enabled']) {
                sc['ActiveInS0'] = (Q('idx_d27activeins0').value == 1);
                sc['AuthenticationProtocol'] = Q('idx_d27protocol').value;
                if (Q('idx_d27roamingidentity').value != '') { sc['RoamingIdentity'] = Q('idx_d27roamingidentity').value; } else { delete sc['RoamingIdentity']; }
                if (Q('idx_d27servername').value != '') {
                    sc['ServerCertificateName'] = Q('idx_d27servername').value;
                    sc['ServerCertificateNameComparison'] = Q('idx_d27servernamecompare').value;
                } else {
                    delete sc['ServerCertificateName'];
                    delete sc['ServerCertificateNameComparison'];
                }
                if (Q('idx_d27username').value != '') { sc['Username'] = Q('idx_d27username').value; } else { delete sc['Username']; }
                if (Q('idx_d27password').value != '') { sc['Password'] = Q('idx_d27password').value; } else { delete sc['Password']; }
                if (Q('idx_d27domain').value != '') { sc['Domain'] = Q('idx_d27domain').value; } else { delete sc['Domain']; }
                if (Q('idx_d27protocol').value > 3) {
                    sc['ProtectedAccessCredential'] = Q('idx_d27pac').value;
                    sc['PACPassword'] = Q('idx_d27pacpassword').value;
                } else {
                    delete sc['ProtectedAccessCredential'];
                    delete sc['PACPassword'];
                }
                if (parseInt(Q('idx_d27clientcert').value) >= 0) { sc['ClientCertificate'] = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + xxCertificates[parseInt(Q('idx_d27clientcert').value)]['InstanceID'] + '</w:Selector></w:SelectorSet></a:ReferenceParameters>'; } else { delete sc['ClientCertificate']; }
                if (parseInt(Q('idx_d27servercert').value) >= 0) { sc['ServerCertificateIssuer'] = '<a:Address>/wsman</a:Address><a:ReferenceParameters><w:ResourceURI>' + amtstack.CompleteName('AMT_PublicKeyCertificate') + '</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">' + xxCertificates[parseInt(Q('idx_d27servercert').value)]['InstanceID'] + '</w:Selector></w:SelectorSet></a:ReferenceParameters>'; } else { delete sc['ServerCertificateIssuer']; }
                sc['PxeTimeout'] = Q('idx_d27pxetimeout').value;
            }
            amtstack.Put('AMT_8021XProfile', sc, setNetAuthProfileEx);
        }

        function setNetAuthProfileEx(stack, name, response, status) {
            if (status == 200) {
                amtsysstate['AMT_8021XProfile'].responses.Body = amtsysstate['AMT_8021XProfile'].response = response.Body;
                updateSystemStatus();
            } else {
                if (response.Header['WsmanError']) {
                    messagebox("802.1x Error", response.Header['WsmanError'].replace(/_/g, ' '));
                } else {
                    messagebox("802.1x Error", "Error, Status = " + status);
                }
            }
        }

// ###END###{NetAuth}
// ###END###{NetworkSettings}

// ###BEGIN###{HardwareInfo}
        //
        // HARDWARE INFORMATION PANEL
        //

        function PullHardware() {
            amtstack.BatchEnum('', ['*CIM_ComputerSystemPackage', 'CIM_SystemPackaging', '*CIM_Chassis', 'CIM_Chip', '*CIM_Card', '*CIM_BIOSElement', 'CIM_Processor', 'CIM_PhysicalMemory', 'CIM_MediaAccessDevice', 'CIM_PhysicalPackage', '*CIM_Battery'], processHardware);
            amtFirstPull |= 1; // Set the hardware info bit on, indicates we are pulling this information.
        }

        // http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
        var DMTFCPUStatus = ["Unknown", "Enabled", "Disabled by User", "Disabled By BIOS (POST Error)", "Idle", "Other"];
        var DMTFMemType = ["Unknown", "Other", "DRAM", "Synchronous DRAM", "Cache DRAM", "EDO", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "Flash", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR-2", "BRAM", "FB-DIMM", "DDR3", "FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4"];
        var DMTFMemFormFactor = ['', "Other","Unknown","SIMM","SIP","Chip","DIP","ZIP","Proprietary Card","DIMM","TSOP","Row of chips","RIMM","SODIMM","SRIMM","FB-DIM"];
        var DMTFProcFamilly = { // Page 46 of DMTF document
            191: "Intel&reg; Core&trade; 2 Duo Processor",
            192: "Intel&reg; Core&trade; 2 Solo processor",
            193: "Intel&reg; Core&trade; 2 Extreme processor",
            194: "Intel&reg; Core&trade; 2 Quad processor",
            195: "Intel&reg; Core&trade; 2 Extreme mobile processor",
            196: "Intel&reg; Core&trade; 2 Duo mobile processor",
            197: "Intel&reg; Core&trade; 2 Solo mobile processor",
            198: "Intel&reg; Core&trade; i7 processor",
            199: "Dual-Core Intel&reg; Celeron&reg; processor" };

        var HardwareInventory;
        function processHardware(stack, name, responses, status) {
            if (status != 200) return;

            var i, x = '<table class=log1 cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px>';
            HardwareInventory = responses;
            QV('go2', true); // Show "Hardware Information" on left panel

            // ###BEGIN###{!FileSaver}
            x += TableEnd('<div>&nbsp;' + AddRefreshButton('PullHardware(1)') + " Hardware information is gathered at system boot time.");
            // ###END###{!FileSaver}
            // ###BEGIN###{FileSaver}
            x += TableEnd('<div>&nbsp;' + AddRefreshButton('PullHardware(1)') + AddButton("Save...", 'SaveHardwareLog()') + " Hardware information is gathered at system boot time.");
            // ###END###{FileSaver}

            var ba = responses['CIM_Chassis'].response;
            var bb = responses['CIM_Card'].response;
            var v = responses['CIM_BIOSElement'].response['SoftwareElementID'];
            
            x += '<br><h2>' + "Platform" + '</h2>';
            x += FullTable({"Computer model":ba['Model'], "Manufacturer":ba['Manufacturer'], "Version":ba['Version'], "Serial number":ba['SerialNumber'], "System ID":guidToStr(responses['CIM_SystemPackaging'].responses[0]['PlatformGUID']).toLowerCase()}, '');

            x += '<br><h2>' + "Baseboard" + '</h2>';
            x += FullTable({"Manufacturer":bb['Manufacturer'], "Product name":bb['Model'], "Version":bb['Version'], "Serial number":bb['SerialNumber'], "Asset tag":bb['Tag'], "Replaceable?":(bb['CanBeFRUed']==true)?'Yes':'No' },'');
            
            x += '<br><h2>' + "BIOS" + '</h2>';
            x += FullTable({"Vendor":responses['CIM_BIOSElement'].response['Manufacturer'], "Version":v, "Release date":new Date(responses['CIM_BIOSElement'].response['ReleaseDate']['Datetime']).toLocaleDateString('en', {timeZone:'UTC'})},'');
            
            x += '<br>';
            for (i in responses['CIM_Processor'].responses) {
                var p = responses['CIM_Processor'].responses[i];
                var q = responses['CIM_Chip'].responses[i]; // This is a shortcut, we assume that the first entries in CIM_Chip are the processors, in the same order.
                x += '<h2>' + "Processor" + ' ' + (parseInt(i) + 1) + '</h2>';
                x += FullTable({"Manufacturer":trademarks(q['Manufacturer']), "Family":DMTFProcFamilly[p['Family']], "Version":trademarks(q['Version']), "Maximum socket speed":p['MaxClockSpeed'] + " MHz", "Status":DMTFCPUStatus[p['CPUStatus']]},'');
            }
            x += '<br>';

            for (i in responses['CIM_PhysicalMemory'].responses) {
                var m = responses['CIM_PhysicalMemory'].responses[i];
                x += '<h2>' + "Memory Module" + ' ' + (+i + 1) + '</h2>';
                x += FullTable({"Bank Label":m['BankLabel'], "Manufacturer":m['Manufacturer'], "Serial Number":m['SerialNumber'], "Size":parseInt(m['Capacity'] / 0x100000) + " MB", "Form factor":DMTFMemFormFactor[m['FormFactor']], "Type":DMTFMemType[m['MemoryType']], "Asset tag":m['Tag'], "Part number":m['PartNumber']},'');
            }
            x += '<br>';

            for (i in responses['CIM_MediaAccessDevice'].responses) {
                var m = responses['CIM_MediaAccessDevice'].responses[i];
                var n = responses['CIM_PhysicalPackage'].responses[+i + 1]; // This is a shortcut, we assume CIM_PhysicalPackage is the same as CIM_MediaAccessDevice except for the first entry.
                x += '<h2>' + "Storage Media" + ' ' + (parseInt(i) + 1) + '</h2>';
                x += FullTable({"Model":n['Model'],"Serial number":(n['SerialNumber']==''?'Unknown':n['SerialNumber']), "Size":parseInt(Math.round(m['MaxMediaSize'] * 1000 / 0x100000)) + " MB"},'');
            }
            x += '<br>';

            if (responses['CIM_Battery'].response != null) {
                var battInfo = null;
                for (i in responses['CIM_PhysicalPackage'].responses) { if (responses['CIM_PhysicalPackage'].responses[i].PackageType == 11) { battInfo = responses['CIM_PhysicalPackage'].responses[i]; } }
                if (battInfo != null) {
                    x += '<h2>' + "Battery" + '</h2>';
                    var battdate = new Date(battInfo['ManufactureDate']['Datetime']).toDateString()
                    var batttype = ["Other", "Unknown", "Lead Acid", "Nickel Cadmium", "Nickel Metal Hydride", "Lithium-ion", "Zinc air", "Lithium Polymer"][responses['CIM_Battery'].response['Chemistry']];
                    var batt = { "Device name": responses['CIM_Battery'].response['DeviceID'], "Manufacturer": battInfo['Manufacturer'], "Manufacture date": battdate, "Serial number": battInfo['SerialNumber'], "Type": batttype, "Design capacity": responses['CIM_Battery'].response['DesignCapacity'] + ' ' + "mWatt-hours", "Design voltage": responses['CIM_Battery'].response['DesignVoltage'] + ' ' + "mVolts" };
                    if (battInfo['OtherIdentifyingInfo']) { batt["Other Info"] = battInfo['OtherIdentifyingInfo']; }
                    x += FullTable(batt, '');
                }
            }
            x += '<br>';

            QH('id_TableSysInfo', x);
            updateSystemStatus();
        }

        // ###BEGIN###{FileSaver}
        function SaveHardwareLog() {
            if (!xxdialogMode && HardwareInventory) SaveJsonFile('IntelAmtHardware', 'hardware', "Intel AMT Hardware Information", HardwareInventory);
        }
        // ###END###{FileSaver}

// ###END###{HardwareInfo}

        //
        // POWER POLICY
        //

        var AmtSystemPowerSchemes = null;
        function PullPowerPolicy() { amtstack.Enum('AMT_SystemPowerScheme', powerPolicyResponse); }
        function powerPolicyResponse(stack, name, response, status) { AmtSystemPowerSchemes = response; updateSystemStatus(); }

        function showPowerPolicyDlg(currentguid) {
            if (xxdialogMode) return;
            var s = '';

            // Now find the name of the power schema in the AMT_SystemPowerScheme table
            for (var j = 0; j < AmtSystemPowerSchemes.length; j++) {
                var selected = ((AmtSystemPowerSchemes[j]['SchemeGUID'] == currentguid)?' checked':'');
                s += '<input type=radio name=powerpolicy value=\"' + AmtSystemPowerSchemes[j]['InstanceID'] + '\" ' + selected + '>' + AmtSystemPowerSchemes[j]['Description'] + '<br>';
            }

            setDialogMode(11, "Intel&reg; AMT Power Policy", 3, showPowerPolicyDlgOk, s);
        }

        function showPowerPolicyDlgOk() {
            var id = null, i = 0, e = document.getElementsByTagName('input');
            for (; i < e.length; i++) { if (e[i].name == 'powerpolicy' && e[i].checked) { id = e[i].value; } }
            amtstack.AMT_SystemPowerScheme_SetPowerScheme(showPowerPolicyDlgOkDone, id);
        }

        function showPowerPolicyDlgOkDone(stack, name, response, status) { if (status == 200) PullSystemStatus(); }

        //
        // USER INFORMATION PANEL
        //

        var xxAccountAdminName, xxAccountRealmInfo, xxAccountEnabledInfo = {}, xxAccountFetch, showHiddenAccounts = false;

        function PullUserInfo() {
            xxAccountFetch = 1;
            delete xxAccountAdminName;
            xxAccountRealmInfo = {};
            amtstack.AMT_AuthorizationService_GetAdminAclEntry(getAdminAclEntryResponse);
            amtstack.AMT_AuthorizationService_EnumerateUserAclEntries(1, enumerateUserAclEntriesResponse);
        }

        function getAdminAclEntryResponse(stack, name, response, status) {
            if (status != 200) return;
            xxAccountRealmInfo[-1] = { 'AccessPermission': 999, 'DigestUsername': response.Body['Username'], 'Realms':null };
            xxAccountAdminName = response.Body['Username'];
            updateAccounts();
        }

        function enumerateUserAclEntriesResponse(stack, name, response, status) {
            if (status != 200) return;
            //if (errcheck(status, stack)) return;
            methodcheck(response);
            QV('go11', true); // Show "User Accounts" on left panel
            xxAccountFetch = response.Body['Handles'].length;
            for (var i in response.Body['Handles']) {
                var h = response.Body['Handles'][i];
                amtstack.AMT_AuthorizationService_GetAclEnabledState(h, getAclEnabledStateResponse, h);
                amtstack.AMT_AuthorizationService_GetUserAclEntryEx(h, getUserAclEntryExResponse, h);
            }
            updateAccounts();
        }

        function getUserAclEntryExResponse(stack, name, response, status, tag) {
            xxAccountFetch--;
            //if (errcheck(status, stack)) return;
            //methodcheck(response);
            if (status == 200) { // Sometimes Intel AMT will just freak out on this call, if it's the case, just carry on.
                response.Body['Handle'] = tag;
                if (!response.Body['Realms']) response.Body['Realms'] = [];
                else if (!Array.isArray(response.Body['Realms'])) response.Body['Realms'] = [response.Body['Realms']]; // If "Realms" is not an array, it's because it's just one realm. Fix is so it's an array of one.
                xxAccountRealmInfo[tag] = response.Body;
                updateAccounts();
            }
        }

        function getAclEnabledStateResponse(stack, name, response, status, tag) {
            //if (errcheck(status, stack)) return;
            if (status == 200) { // Sometimes Intel AMT will just freak out on this call, if it's the case, just carry on.
                xxAccountEnabledInfo[tag] = response.Body;
                updateAccounts();
            }
        }

        function setAclEnabledStateResponse(stack, name, response, status, tag) {
            if (errcheck(status, stack)) return;
            methodcheck(response);
            amtstack.AMT_AuthorizationService_GetAclEnabledState(tag, getAclEnabledStateResponse, tag);
        }

        function updateAccounts() {
            if (xxAccountFetch > 0) return;
            var x = TableStart2();
            x += '<tr><td class=r1 style=padding-left:15px><br>' + "Manage the Intel&reg; AMT user accounts for this computer." + '<br><br>';
            for (var i in xxAccountRealmInfo) {
                var r = xxAccountRealmInfo[i], name, hidden = false, state = 0;
                if (r['DigestUsername']) { name = r['DigestUsername']; hidden = (name[0] == '$' && name[1] == '$'); } else { name = GetSidString(atob(r['KerberosUserSid'])); }
                if (xxAccountEnabledInfo[i] && name != '$$OsAdmin') { state = (xxAccountEnabledInfo[i]['Enabled'] == true)?1:2; }
                if (showHiddenAccounts || !hidden) {
                    var rb = '';
                    if (r['AccessPermission'] != 999) {
                        if (state == 2) { rb += "Disabled, "; }
                        var rc = 0;
                        for (i in r['Realms']) { if (amtstack.RealmNames[r["Realms"][i]] != '') { rc++; } } // Count only realms that have a name, removing reserved realms.
                        if (r['Realms'].indexOf(20) >= 0) rb += "Auditor, ";
                        if (r['Realms'].indexOf(3) >= 0) { rb += "Administrator"; } else { if (rc == 1) { rb += "1 realm"; } else { rb += rc + " realms"; } }
                    } else {
                        rb += "Administrator";
                        r['Handle'] = -1;
                    }
                    x += '<div class=itemBar onclick=showUserDetails(' + r['Handle'] + ')><div style=float:right>';
                    if (state > 0 && xxAccountAdminName) x += ' ' + AddButton2((state == 1?'Disable':'Enable'), 'changeAccountStateButton(event,' + r['Handle'] + ',' + state + ')');
                    if (!hidden && xxAccountAdminName) x += ' ' + AddButton2("Edit...", 'changeAccountButton(event,' + r['Handle'] + ')');
                    x += '</div><div style=padding-top:3px;width:330px;float:left;overflow-x:hidden title="' + name + '"><b>' + name + '</b></div><div style=padding-top:3px>' + rb + '</div></div>';
                }
            }
            var y = '<div style=float:right;margin-right:8px><a title="' + "Toggle hidden accounts" + '" style=color:gray;cursor:pointer onclick=toggleAccountButton()>' + (showHiddenAccounts?'&#x25B2;':'&#x25BC;') + '</a></div><div>&nbsp;' + AddRefreshButton('xxAccountFetch=999;PullUserInfo()');
            if (xxAccountAdminName) y += AddButton("New Account", 'newAccountButton()');
            x += '<br><td class=r1>' + TableEnd(y + '</div>');
            QH('id_TableUserAccounts', x);
        }

        function toggleAccountButton() {
            showHiddenAccounts = !showHiddenAccounts;
            updateAccounts();
        }

        function removeUserAclEntryResponse(stack, name, response, status, tag) {
            if (methodcheck(response)) return;
            PullUserInfo();
        }

        function changeAccountStateButton(e, h, s) {
            haltEvent(e);
            if (xxdialogMode) return;
            amtstack.AMT_AuthorizationService_SetAclEnabledState(h, (s==1?false:true), setAclEnabledStateResponse, h);
        }

        function changeAccountButton(e, h) {
            haltEvent(e);
            if (xxdialogMode) return;
            updateRealms(xxAccountRealmInfo[h]['Realms']);
            d2username.value = xxAccountRealmInfo[h]['DigestUsername'] ? xxAccountRealmInfo[h]['DigestUsername'] : GetSidString(atob(xxAccountRealmInfo[h]['KerberosUserSid']));
            d2password1.value = d2password2.value = '';
            d2permission.value = xxAccountRealmInfo[h]['AccessPermission'];
            setDialogMode(2, "Edit Account", ((h==-1)?3:7), function (button) { changeAccountButtonEx(h, button); }); // If handle is -1, only display OK/Cancel buttons, if not, also display delete button.
            updateAccountDialog();
        }

        function newAccountButton() {
            if (xxdialogMode) return;
            updateRealms([]);
            d2username.value = d2password1.value = d2password2.value = '';
            d2permission.value = 2;
            setDialogMode(2, "New Account", 3, function () { changeAccountButtonEx(null, 1); });
            updateAccountDialog();
        }

        function changeAccountButtonEx(h, button) {
            if (button == 1) { // OK Button
                var realms = [], username = d2username.value, permission = d2permission.value, password = d2password1.value, sid = GetSidByteArray(Q('d2username').value), d = null;
                if (username.length == 0 || password != d2password2.value) { messagebox("Account Error", "Invalid Parameters"); return; }
                if (sid == null) { d = window.btoa(rstr_md5(username + ":" + amtsysstate['AMT_GeneralSettings'].response['DigestRealm'] + ":" + password)); } else { username = null; sid = btoa(sid); }
                if (h != -1) { for (var y in amtstack.RealmNames) { if (((amtstack.RealmNames[y]) || (y == 3)) && Q('rx' + y).checked) { realms.push(y); } } }
                if (h == null) { amtstack.AMT_AuthorizationService_AddUserAclEntryEx(username, d, sid, permission, realms, userAclEntryExResponse); }
                else if (h == -1) { amtstack.AMT_AuthorizationService_SetAdminAclEntryEx(username, d, userAclEntryExResponse); }
                else { amtstack.AMT_AuthorizationService_UpdateUserAclEntryEx(h, username, d, sid, permission, realms, userAclEntryExResponse); }
            }
            if (button == 2) { // Delete Button
                amtstack.AMT_AuthorizationService_RemoveUserAclEntry(h, removeUserAclEntryResponse);
            }
        }

        function userAclEntryExResponse(stack, name, response, status, tag) { if (methodcheck(response)) return; PullUserInfo(); }
        function updateRealms(r) {
            QV('id_d2permissions', r != null);
            if (r != null) {
                var x = '<li><label><input type=checkbox onchange=updateAccountDialog() id=rx3' + ((r.indexOf(3) >= 0)?' checked':'') + '>' + "Administrator" + '</label></li><hr />';
                for (var y in amtstack.RealmNames) { var c = ''; if (r.indexOf(parseInt(y)) >= 0) c = ' checked'; if (amtstack.RealmNames[y]) x += '<li><label><input type=checkbox onchange=updateAccountDialog() id=rx' + y + c + '>' + amtstack.RealmNames[y] + '</label></li>'; }
                QH('id_d2realms', x);
            }
        }

        function updateAccountDialog() {
            var ok = true;
            if (Q('id_d2permissions').style.display != 'none') { ok = false; for (var y in amtstack.RealmNames) { if (((amtstack.RealmNames[y]) || (y == 3)) && Q('rx' + y).checked) { ok = true; } } }
            if (ok) { ok = ((d2username.value.length > 0) && (passwordcheck(d2password1.value)) && (d2password1.value == d2password2.value)); }
            QE('idx_dlgOkButton', ok);
        }

        var xxUserPermissions = ["Local only" , "Network only", "All (Local & Network)"];
        function showUserDetails(h) {
            if (xxdialogMode) return;
            var a = xxAccountRealmInfo[h], x = '<div style=text-align:left>';
            var i, n = a['DigestUsername'];
            if (!n) n = GetSidString(atob(a['KerberosUserSid']));
            x += addHtmlValue("Name", n);
            if (xxAccountEnabledInfo[h]) { x += addHtmlValue("State", ((xxAccountEnabledInfo[h]['Enabled'] == true)?"Enabled":"Disabled")); }
            if (n == xxAccountAdminName) {
                x += addHtmlValue("Permission", "Administrator");
            } else {
                x += addHtmlValue("Permission", xxUserPermissions[a['AccessPermission']]);
                var y = '';
                if (a['Realms'].indexOf(3) >= 0) {
                    y = "Administrator";
                    if (a['Realms'].indexOf(20) >= 0) y += ", Auditor";
                } else {
                    for (i in xxAccountRealmInfo[h]['Realms']) {
                        if (amtstack.RealmNames[a['Realms'][i]] != '') { // Remove blank reserved realms
                            if (y.length > 0) y += ", ";
                            y += amtstack.RealmNames[a['Realms'][i]];
                        }
                    }
                }
                if (y.length == 0) y = "None";
                x += addHtmlValue("Realms", '') + '<b>' + y + '</b>';
            }
            x += '</div>';
            messagebox("Account " + n, x);
        }

        //
        // WSMAN BROWSER PANEL
        //

        // ###BEGIN###{WsmanBrowser}
        function wsmanQuery() {
            QH('id_wsresults', '');
            var selections = getSelectedOptions(Q('id_QuerySelect')), selections2 = [];
            for (var x in selections) { if (QS('WSB-' + selections[x]).display == '') selections2.push(selections[x]); }
            if (selections2.length == 0) return;
            QE('id_p12querybutton', false);
            if (selections2 && selections2.length > 0) { amtstack.BatchEnum("Browser", selections2, browserResponse, null, true); } // This is the only BatchEnum where we want to continue and get an answer even if one of the calls fails.
        }

        function browserResponse(stack, name, responses, status) {
            QE('id_p12querybutton', true);
            var h = '';
            for (var r in responses) {
                var response = responses[r];
                h += '<h2>' + r + '</h2><div style=margin-left:20px>';
                if (response.status == 200) { if (response.responses.length == 0) { h += ('<br>' + "(Empty)"); } else { h += ObjectToString(response.responses).replace(/Intel\(r\)/g, 'Intel&reg'); } } else { h += '<br><div style=color:red>' + "Error #" + response.status + '</div>'; }
                h += '</div><br>';
            }
            QH('id_wsresults', h);
        }

        function wsmanFilter() {
            var filter = idx_browserFilter.value.toLowerCase();
            for (var w in AllWsman) { QV('WSB-' + AllWsman[w], filter == '' || AllWsman[w].toLowerCase().indexOf(filter) >= 0); }
        }
        // ###END###{WsmanBrowser}

        //
        // Remote Terminal
        //

        // ###BEGIN###{Terminal}
        function connectTerminal() {
            if (!terminal) return;
            if (terminal.State == 0) {
                // ###BEGIN###{ComputerSelector}
                terminal.digestRealmMatch = amtstack.wsman.comm.digestRealm;
                // ###END###{ComputerSelector}
                // ###BEGIN###{Mode-MeshCentral2}
                terminal.tlsv1only = amtstack.wsman.comm.tlsv1only;
                terminal.Start(currentMeshNode._id, 16994, '*', '*', 0);
                // ###END###{Mode-MeshCentral2}
                // ###BEGIN###{ComputerSelector}
                // ###BEGIN###{Mode-NodeWebkit}

                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer != null) {
                    terminal.Start(currentcomputer._id, 0, 'x', 'x', 0, wsstack.comm, meshCentralServer);
                } else {
                    // ###END###{MeshServerConnect}
                    var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls'])
                    terminal.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls'], wsstack.comm.getPeerCertificateFingerprint(), wsstack.comm.xtlsoptions);
                    // ###BEGIN###{MeshServerConnect}
                }
                // ###END###{MeshServerConnect}

                // ###END###{Mode-NodeWebkit}
                // ###BEGIN###{!Mode-NodeWebkit}
                terminal.tlsv1only = amtstack.wsman.comm.tlsv1only;
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls'])
                terminal.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls']);
                // ###END###{!Mode-NodeWebkit}
                // ###END###{ComputerSelector}
                // ###BEGIN###{Mode-Firmware}
                terminal.Start();
                // ###END###{Mode-Firmware}
            } else {
                terminal.Stop();
            }
        }

        function onTerminalStateChange(terminal, state) {
            // console.log("onTerminalStateChange: " + state);
            idx_connectbutton2.value = (state == 0) ? "Connect" : "Disconnect";
            Q('id_termstatus').textContent = StatusStrs[state];
            QE('id_tpastebutton', state == 3);
            // ###BEGIN###{!Mode-NodeWebkit}
            QE('TermWD', state == 3);
            // ###END###{!Mode-NodeWebkit}
            switch (state) {
                case 0:
                    terminal.m.TermResetScreen();
                    terminal.m.TermDraw();
                    if (xxdialogMode == 3) setDialogMode();
                    // ###BEGIN###{Mode-MeshCentral2}
                    QV('termRecordIcon', false);
                    // ###END###{Mode-MeshCentral2}
                    if (terminal.disconnectCode == 2) { // BUSY
                        messagebox("Remote Terminal", "The remote device is busy, a session may already be open.");
                    } else if (terminal.disconnectCode == 3) { // UNSUPPORTED
                        messagebox("Remote Terminal", "The device indicated that this type of connection of not supported.");
                    }
                    break;
                case 3:
                    // ###BEGIN###{Mode-MeshCentral2}
                    if (terminal.serverIsRecording == true) { QV('termRecordIcon', true); }
                    // ###END###{Mode-MeshCentral2}
                    break;
            }
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(currentView);
            // ###END###{Mode-NodeWebkit}
        }

        function termPaste() { terminal.m.TermSendKeys(d3pastetextarea.value); return false; }
        function termSendKey(k) { terminal.m.TermSendKey(k); return false; }
        function termSendKeys() { var k = Q('termkeys').value; if (k < 1000) { termSendKey(k); } else { terminal.m.TermHandleKeyDown({ which: k - 889, repeat: false }); } }

        // ###BEGIN###{TerminalSize}
        function termToggleSize() {
            if (terminal.m.width == 80) {
                Q('id_tsizebutton').value = '100x30';
                terminal.m.Init(100, 30);
            } else {
                Q('id_tsizebutton').value = '80x25';
                terminal.m.Init(80, 25);
            }
        }
        // ###END###{TerminalSize}

        // ###BEGIN###{Terminal-Enumation-All}
        var terminalEmulations = ["UTF8 Terminal", "Extended ASCII", "Intel ASCII"];
        function termToggleType() {
            terminal.m.terminalEmulation = (terminal.m.terminalEmulation + 1) % 3;
            Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
        }
        // ###END###{Terminal-Enumation-All}

        // ###BEGIN###{Terminal-FxEnumation-All}
        function termToggleFx() {
            Q('id_tfxkeysbutton').value = ["Intel (F10 = ESC+[OM)", "Alternate (F10 = ESC+0)", "VT100+ (F10 = ESC+[OY)"][terminal.m.fxEmulation = (terminal.m.fxEmulation + 1) % 3];
        }
        // ###END###{Terminal-FxEnumation-All}

        function termToggleCr() {
            if (terminal.m.lineFeed == '\r\n') {
                Q('id_tcrbutton').value = "LF";
                terminal.m.lineFeed = '\n';
            } else {
                Q('id_tcrbutton').value = "CR+LF";
                terminal.m.lineFeed = '\r\n';
            }
        }

        // ###BEGIN###{FileSaver}
        function terminalCaptureToggle(e) {
            if (xxdialogMode) return;
            // ###BEGIN###{TerminalReplay}
            if ((e != null) && (e.shiftKey == true)) { terminalReplay(); return; }
            if (terminalReplayTimer != null) { return; }
            // ###END###{TerminalReplay}
            if (terminal.m.capture == undefined) {
                terminal.m.capture = ''; // Start terminal capture
                // ###BEGIN###{!Mode-NodeWebkit}
                idx_terminalCaptureButton.value = "Stop Capture";
                // ###END###{!Mode-NodeWebkit}
            } else {
                if (terminal.m.capture.length > 0) {
                    var n = 'TerminalCapture', d = new Date();
                    if (amtsysstate) { n += '-' + amtsysstate['AMT_GeneralSettings'].response['HostName']; }
                    n += '-' + d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
                    // ###BEGIN###{!Mode-NodeWebkit}
                    saveAs(data2blob(terminal.m.capture), n + '.txt');
                    delete terminal.m.capture;
                    idx_terminalCaptureButton.value = "Start Capture";
                    // ###END###{!Mode-NodeWebkit}
                    // ###BEGIN###{Mode-NodeWebkit}
                    var chooser = document.createElement('input');
                    chooser.setAttribute('type', 'file');
                    chooser.setAttribute('nwsaveas', n + '.txt');
                    chooser.addEventListener('change', function() {
                        require('fs').writeFile(this.value, terminal.m.capture, function () { });
                        delete terminal.m.capture;
                    }, false);
                    chooser.click();
                    // ###END###{Mode-NodeWebkit}
                } else {
                    delete terminal.m.capture;
                    // ###BEGIN###{!Mode-NodeWebkit}
                    idx_terminalCaptureButton.value = "Start Capture";
                    // ###END###{!Mode-NodeWebkit}
                }
            }
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(currentView);
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

        // ###BEGIN###{TerminalReplay}
        function terminalReplay() {
            if (xxdialogMode) return;
            if (terminalReplayTimer != null) {
                clearInterval(terminalReplayTimer); terminalReplayBuffer = null; terminalReplayBufferPtr = 0; terminalReplayTimer = null;
                // ###BEGIN###{Mode-NodeWebkit}
                NW_SetupMainMenu(currentView);
                // ###END###{Mode-NodeWebkit}
            } else {
                setDialogMode(11, "Open Terminal Capture", 3, terminalReplayEx, '<input id=termCaptureFile type=file style=width:100% accept=.txt>');
            }
        }

        function terminalReplayEx() {
            var x = Q('termCaptureFile');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = terminalReplayEx2;
            reader.readAsBinaryString(x.files[0]);
        }

        var terminalReplayBuffer = null;
        var terminalReplayBufferPtr = 0;
        var terminalReplayTimer = null;
        function terminalReplayEx2(file) {
            terminal.m.TermResetScreen();
            if (terminalReplayTimer != null) { clearInterval(terminalReplayTimer); terminalReplayTimer = null; }
            terminalReplayBufferPtr = 0;
            terminalReplayBuffer = file.target.result;
            terminalReplayTimer = setInterval(terminalReplayEx3, 5);
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(currentView);
            // ###END###{Mode-NodeWebkit}
        }

        function terminalReplayEx3() {
            var len = ((terminalReplayBufferPtr - 1) < terminalReplayBuffer.length) ? 2 : 1;
            var x = terminalReplayBuffer.substring(terminalReplayBufferPtr, terminalReplayBufferPtr + len);
            terminal.m.ProcessData(x);
            terminalReplayBufferPtr += len;
            if (terminalReplayBufferPtr >= terminalReplayBuffer.length) {
                clearInterval(terminalReplayTimer); terminalReplayBuffer = null; terminalReplayBufferPtr = 0; terminalReplayTimer = null;
                // ###BEGIN###{Mode-NodeWebkit}
                NW_SetupMainMenu(currentView);
                // ###END###{Mode-NodeWebkit}
            }
        }

        // ###END###{TerminalReplay}

        function terminal_FileSelectHandler(e) {
            haltEvent(e);
            if (terminal.State != 3 || e.dataTransfer == null || e.dataTransfer.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = terminal_onSetupBinRead;
            reader.readAsText(e.dataTransfer.files[0]);
        }

        function terminal_onSetupBinRead(file) {
            d3pastetextarea.value = file.target.result;
            setDialogMode(3, "Paste", 3, termPaste)
        }

        // ###END###{Terminal}

        //
        // Remote Desktop
        //

        // ###BEGIN###{Desktop}

        // ###BEGIN###{Desktop-Multi}
        var desktopScreenInfo = null;
        var desktopPollTimer = null;
        // ###END###{Desktop-Multi}
        // ###BEGIN###{DesktopInband}
        var webRtcDesktop = null;
        function webRtcDesktopReset() {
            if (webRtcDesktop == null) return;
            if (webRtcDesktop.softdesktop != null) { webRtcDesktop.softdesktop.Stop(); webRtcDesktop.softdesktop = null; }
            if (webRtcDesktop.webchannel != null) { try { webRtcDesktop.webchannel.close(); } catch (e) { } webRtcDesktop.webchannel = null; }
            if (webRtcDesktop.webrtc != null) { try { webRtcDesktop.webrtc.close(); } catch (e) { } webRtcDesktop.webrtc = null; }
            webRtcDesktop = null;
            // Switch back to hardware KVM
            desktop.m.hold(false);
            updateDesktopState();
            // ###BEGIN###{DesktopInbandFiles}
            p24files = null;
            p24downloadFileCancel() // If any downloads are in process, cancel them.
            p24uploadFileCancel(); // If any uploads are in process, cancel them.
            QV('go24', false); // Files
            if (currentView == 24) { go(14); }
            // ###END###{DesktopInbandFiles}
        }

        /*
        function webRtcDesktopProcessData(data) {
            console.log('WebRTC data, len = ' + data.length);
        }
        */
        // ###END###{DesktopInband}

        function connectDesktopButton(e) { desktop.disconnectCode = 0; connectDesktop(e); }

        var connectDesktopConsent = false;
        function connectDesktop(skipConsent) {
            if (!desktop || xxdialogMode) return;
            connectDesktopConsent = false; // TODO, this is not a good idea when calls are pending.
            if (desktop.State == 0) {
                // Check if user consent is needed
                if ((skipConsent !== true) && (amtversion > 5) && ((amtsysstate == null) || (amtsysstate != null) && (amtsysstate['IPS_OptInService'] != null) && (amtsysstate['IPS_OptInService'].response != null) && (amtsysstate['IPS_OptInService'].response['OptInRequired'] != 0))) {
                    connectDesktopConsent = true; amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1); return; // User consent always required, ask for it before KVM.
                }
                // Encoding Flags: 1 = RLE, 2 = 16bit, 4 = Gray, 8 = ZLib, 16 = 4bit Color
                desktop.m.useRLE = ((desktopsettings.encflags & 1) != 0);
                desktop.m.bpp = (desktopsettings.encflags & 2) ? 2 : 1;
                if ((amtversion > 15) && (amtsysstate != null) && (amtsysstate['IPS_KVMRedirectionSettingData'] != null) && (amtsysstate['IPS_KVMRedirectionSettingData'].response)) {
                    desktop.m.lowcolor = amtsysstate['IPS_KVMRedirectionSettingData'].response['GrayscalePixelFormatSupported'] && ((desktopsettings.encflags & 16) != 0);
                    desktop.m.graymode = amtsysstate['IPS_KVMRedirectionSettingData'].response['GrayscalePixelFormatSupported'] && ((desktopsettings.encflags & 4) != 0);
                    desktop.m.useZLib = amtsysstate['IPS_KVMRedirectionSettingData'].response['ZlibControlSupported'] && ((desktopsettings.encflags & 8) != 0);
                    desktop.m.decimationMode = ((amtsysstate['IPS_KVMRedirectionSettingData'].response['InitialDecimationModeForLowRes'] > 0) ? desktopsettings.decimationMode : 0);
                } else {
                    desktop.m.lowcolor = false;
                    desktop.m.graymode = false;
                    desktop.m.useZLib = false;
                    desktop.m.decimationMode = 0;
                }
                desktop.m.showmouse = desktopsettings.showmouse;
                desktop.m.onScreenSizeChange = center;
                // ###BEGIN###{ComputerSelector}
                desktop.digestRealmMatch = amtstack.wsman.comm.digestRealm;
                // ###END###{ComputerSelector}
                // ###BEGIN###{DesktopInband}
                desktop.m.onKvmData = function(x) {
                    //console.log('onKvmData (' + x.length + '): ' + x);
                    var data = null;
                    try { data = JSON.parse(x); } catch (e) {}
                    if ((data != null) && (data.action != null)) {
                        if (data.action == 'restart') {
                            // Clear WebRTC channel
                            webRtcDesktopReset();
                            desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 }));
                        } else if ((data.action == 'present') && (webRtcDesktop == null)) {
                            // Setup WebRTC channel
                            webRtcDesktop = { platform: data.platform };
                            var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
                            if (typeof RTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new RTCPeerConnection(configuration); }
                            else if (typeof webkitRTCPeerConnection !== 'undefined') { webRtcDesktop.webrtc = new webkitRTCPeerConnection(configuration); }

                            webRtcDesktop.webchannel = webRtcDesktop.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
                            webRtcDesktop.webchannel.onopen = function () {
                                // Switch to software KVM
                                if (urlvars && urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Open'); }
                                desktop.m.hold(true);
                                webRtcDesktop.webRtcActive = true;
                                webRtcDesktop.softdesktop = CreateKvmDataChannel(webRtcDesktop.webchannel, CreateAgentRemoteDesktop('Desk', Q('id_mainarea')), desktop.m);
                                webRtcDesktop.softdesktop.m.setRotation(desktop.m.rotation);
                                if (desktopsettings.quality) { webRtcDesktop.softdesktop.m.CompressionLevel = desktopsettings.quality; } // Number from 1 to 100. 50 or less is best.
                                if (desktopsettings.scaling) { webRtcDesktop.softdesktop.m.ScalingLevel = desktopsettings.scaling; }
                                webRtcDesktop.softdesktop.Start();
                                updateDesktopState();

                                // Check if we can get remote file access
                                // ###BEGIN###{DesktopInbandFiles}
                                QV('go24', true); // Files
                                downloadFile = null;
                                p24files = webRtcDesktop.softdesktop;
                                p24targetpath = '';
                                webRtcDesktop.softdesktop.onControlMsg = onFilesControlData;
                                webRtcDesktop.softdesktop.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: '' })); // Ask for the root folder
                                // ###END###{DesktopInbandFiles}
                            }
                            webRtcDesktop.webchannel.onclose = function (event) { if (urlvars['kvmdatatrace']) { console.log('WebRTC Data Channel Closed'); } webRtcDesktopReset(); }
                            webRtcDesktop.webrtc.onicecandidate = function (e) {
                                if (e.candidate == null) {
                                    desktop.m.sendKvmData(JSON.stringify({ action: 'offer', ver: 1, sdp: webRtcDesktop.webrtcoffer.sdp }));
                                } else {
                                    webRtcDesktop.webrtcoffer.sdp += ('a=' + e.candidate.candidate + '\r\n'); // New candidate, add it to the SDP
                                }
                            }
                            webRtcDesktop.webrtc.oniceconnectionstatechange = function () {
                                if ((webRtcDesktop != null) && (webRtcDesktop.webrtc != null) && ((webRtcDesktop.webrtc.iceConnectionState == 'disconnected') || (webRtcDesktop.webrtc.iceConnectionState == 'failed'))) { /*console.log('WebRTC ICE Failed');*/ webRtcDesktopReset(); }
                            }
                            webRtcDesktop.webrtc.createOffer(function (offer) {
                                // Got the offer
                                webRtcDesktop.webrtcoffer = offer;
                                webRtcDesktop.webrtc.setLocalDescription(offer, function () { }, webRtcDesktopReset);
                            }, webRtcDesktopReset, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
                        } else if ((data.action == 'answer') && (webRtcDesktop != null)) {
                            // Complete the WebRTC channel
                            webRtcDesktop.webrtc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: data.sdp }), function () { }, webRtcDesktopReset);
                        }
                    }
                };
                if ((amtversion > 15) || urlvars['kvmext']) { desktop.m.kvmExtChanged = updateDesktopState; } else { desktop.m.kvmExtChanged = null; }
                // ###END###{DesktopInband}
                desktop.m.frameRateDelay = ((desktopsettings.limitFrameRate == true)?200:0);
                desktop.m.noMouseRotate = desktopsettings.noMouseRotate;
                desktop.m.ReverseMouseWheel = desktopsettings.reverseMouseWheel;
                // ###BEGIN###{Mode-MeshCentral2}
                desktop.tlsv1only = amtstack.wsman.comm.tlsv1only;
                desktop.Start(currentMeshNode._id, 16994, '*', '*', 0);
                // ###END###{Mode-MeshCentral2}
                // ###BEGIN###{ComputerSelector}
                // ###BEGIN###{Mode-NodeWebkit}

                // ###BEGIN###{MeshServerConnect}
                if (meshCentralServer != null) {
                    desktop.Start(currentcomputer._id, 0, 'x', 'x', 0, wsstack.comm, meshCentralServer);
                } else {
                // ###END###{MeshServerConnect}
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
                if ((amtsysstate) && (amtsysstate['IPS_ScreenConfigurationService'] != null) && ((amtsysstate['IPS_ScreenConfigurationService'].response['EnabledState'] & 1) != 0)) {
                    amtstack.IPS_ScreenConfigurationService_SetSessionState(Q('id_DeskSB').checked == true ? 1 : 0, 3, function (stack, name, responses, status) {
                        if (status != 200) { Q('id_DeskSB').checked = false; } // Screen blanking command is not supported, uncheck the screen blanking
                        desktop.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls'], wsstack.comm.getPeerCertificateFingerprint(), wsstack.comm.xtlsoptions);
                    });
                } else {
                    desktop.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls'], wsstack.comm.getPeerCertificateFingerprint(), wsstack.comm.xtlsoptions);
                }
                // ###BEGIN###{MeshServerConnect}
                }
                // ###END###{MeshServerConnect}


                // ###END###{Mode-NodeWebkit}
                // ###BEGIN###{!Mode-NodeWebkit}
                desktop.tlsv1only = amtstack.wsman.comm.tlsv1only;
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
                if ((amtsysstate) && (amtsysstate['IPS_ScreenConfigurationService'] != null) && ((amtsysstate['IPS_ScreenConfigurationService'].response['EnabledState'] & 1) != 0)) {
                    amtstack.IPS_ScreenConfigurationService_SetSessionState(Q('id_DeskSB').checked == true ? 1 : 0, 3, function (stack, name, responses, status) {
                        if (status != 200) { Q('id_DeskSB').checked = false; } // Screen blanking command is not supported, uncheck the screen blanking
                        desktop.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls']);
                    });
                } else {
                    desktop.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls']);
                }
                // ###END###{!Mode-NodeWebkit}
                // ###END###{ComputerSelector}
                // ###BEGIN###{Mode-Firmware}
                desktop.Start();
                // ###END###{Mode-Firmware}
                // ###BEGIN###{Desktop-Multi}
                PullDesktopDisplayInfo();

                if (!urlvars['norefresh']) { desktopPollTimer = setInterval(PullDesktopDisplayInfo, 5000); }

                // ###END###{Desktop-Multi}
            } else {
                desktop.Stop();
                // ###BEGIN###{Desktop-Multi}
                clearInterval(desktopPollTimer);
                desktopPollTimer = null;
                PullDesktopDisplayInfo();
                // ###END###{Desktop-Multi}
                // ###BEGIN###{DesktopInband}
                webRtcDesktopReset();
                // ###END###{DesktopInband}
            }
        }

        // ###BEGIN###{Desktop-Multi}
        function PullDesktopDisplayInfo() {
            if ((amtversion > 7) && (desktop.State > 0)) { amtstack.BatchEnum('', ['*IPS_ScreenSettingData', '*IPS_KVMRedirectionSettingData'], ProcessDesktopDisplayInfo); } else { desktopScreenInfo = null; Q('id_DeskScreenSelector').innerHTML = '' }
        }

        // Update the currently active displays
        function ProcessDesktopDisplayInfo(stack, name, responses, status) {
            if (status != 200) { desktopScreenInfo = null; return; }
            desktopScreenInfo = responses['IPS_ScreenSettingData'].responses.Body;
            desktopScreenInfo.KVMRSD = responses['IPS_KVMRedirectionSettingData'].responses.Body;
            UpdateDesktopDisplayInfo();
        }

        // Update screen icons
        function UpdateDesktopDisplayInfo() {
            var buttons = '', activeScreens = 0;
            for (var i = 0; i < 3; i++) { if (desktopScreenInfo['IsActive'][i] == true) { activeScreens++; buttons += '<input type="button" ' + ((i == desktopScreenInfo.KVMRSD['DefaultScreen'])?'style="background-color:DodgerBlue"':'') + ' value="' + (i + 1) + '" title="Switch to screen ' + (i + 1) + '" onkeypress="return false" onkeydown="return false" onclick="desktopSwitchScreen(' + i + ')">&nbsp;'; } }
            if (activeScreens > 1) { Q('id_DeskScreenSelector').innerHTML = buttons + '&nbsp;'; } else { Q('id_DeskScreenSelector').innerHTML = ''; }
        }

        // Request switch to a different desktop
        function desktopSwitchScreen(x) {
            var k = Clone(desktopScreenInfo.KVMRSD); k['DefaultScreen'] = x; amtstack.Put('IPS_KVMRedirectionSettingData', k, desktopSwitchScreenEx);
        }

        // Response to request for a different desktop
        function desktopSwitchScreenEx(stack, name, responses, status) {
            if (status == 200) { desktopScreenInfo.KVMRSD = responses.Body; UpdateDesktopDisplayInfo(); }
        }
        // ###END###{Desktop-Multi}

        function onDesktopStateChange(desktop, state) {
            var reconnect = false;
            //console.log("onDesktopStateChange: " + state);
            idx_connectbutton1.value = (state == 0) ? "Connect" : "Disconnect";
            var input = ((state == 3) && !urlvars['kvmviewonly']);
            QE('id_DeskCAD', input);
            QE('deskkeys', input);
            QE('DeskWD', input);
            // ###BEGIN###{DesktopType}
            QE('id_DeskType', input);
            // ###END###{DesktopType}
            // ###BEGIN###{DesktopClipboard}
            QE('id_DeskKvmClipButton', state == 3);
            // ###END###{DesktopClipboard}
            switch (state) {
                case 0:
                    // ###BEGIN###{DesktopRecorder}
                    if (desktop.m.recordedData != null) { deskRecordSession(); }
                    // ###END###{DesktopRecorder}
                    // desktop.m.ResetScreen();
                    // ###BEGIN###{DesktopInband}
                    webRtcDesktopReset();
                    // ###END###{DesktopInband}
                    // ###BEGIN###{Mode-MeshCentral2}
                    QV('deskRecordIcon', false);
                    // ###END###{Mode-MeshCentral2}
                    if (desktop.disconnectCode == 2) { // BUSY
                        messagebox("Remote Desktop", "The remote device is busy, a session may already be open.");
                    } else if (desktop.disconnectCode == 3) { // UNSUPPORTED
                        messagebox("Remote Desktop", "The device indicated that this type of connection of not supported.");
                    } else if (desktop.disconnectCode == 50000) { // KVM-Disconnect
                        messagebox("Remote Desktop", "KVM disconnection, this may indicate that Intel AMT is unable to capture the display (Try RLE8 encoding), or unsupported GPU.");
                    } else if (desktop.disconnectCode == 50001) { // Intel AMT disconnect, try to connect again if connection was more than 5 seconds long.
                        reconnect = (desktop.connectTime != null) && ((desktop.connectTime + 5000) < Date.now());
                        //console.log(desktop.disconnectCode, reconnect);
                    } else if (desktop.disconnectCode == 50002) { // KVM-BufferOverflow
                        messagebox("Remote Desktop", "KVM disconnection that may be due to the display size and resolution being too large for the Intel AMT KVM buffer. Try RLE8 encoding or reducing the display resolution.");
                    }
                    break;
                case 3:
                    // ###BEGIN###{DesktopInband}
                    if (amtversion >= 12) { desktop.m.sendKvmData(JSON.stringify({ action: 'present', ver: 1 })); } // If this is Intel AMT 12 or higher, send the soft-KVM presence indicator.
                    // ###END###{DesktopInband}
                    // ###BEGIN###{Mode-MeshCentral2}
                    if (desktop.serverIsRecording == true) { QV('deskRecordIcon', true); }
                    // ###END###{Mode-MeshCentral2}
                    break;
            }
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(currentView);
            // ###END###{Mode-NodeWebkit}
            center();
            updateDesktopState();
            if (reconnect) { setTimeout(connectDesktop, 200); }
        }

        // Update remote desktop status
        function updateDesktopState() {
            // ###BEGIN###{DesktopInband}
            var x = '';
            if (desktop.State == 3) {
                if ((webRtcDesktop) && (webRtcDesktop.webRtcActive == true)) {
                    x = ", Soft-KVM";
                } else {
                    if (desktop.m && desktop.m.kvmExt) {
                        if (desktop.m.kvmExt.decimationState == 1) { x += ", Downscaled" }
                        if (desktop.m.kvmExt.compression == 1) { x += ", Compressed" }
                    }
                }
            }
            Q('id_deskstatus').textContent = StatusStrs[desktop.State] + x;
            // ###END###{DesktopInband}
            // ###BEGIN###{!DesktopInband}
            Q('id_deskstatus').textContent = StatusStrs[desktop.State];
            // ###END###{!DesktopInband}
        }

        function showDesktopSettings() {
            if (xxdialogMode) return;
            applyDesktopSettings();
            setDialogMode(7, "Remote Desktop Settings", 3, showDesktopSettingsChanged);
        }

        function showDesktopSettingsChanged() {
            desktopsettings.encflags = parseInt(idx_d7desktopmode.value);
            // ###BEGIN###{DesktopFocus}
            desktopsettings.showfocus = d7showfocus.checked;
            if ((amtversion > 15) && (amtsysstate['IPS_KVMRedirectionSettingData'].response['InitialDecimationModeForLowRes'] > 0)) { desktopsettings.decimationMode = parseInt(d7decimation.value); }
            // ###END###{DesktopFocus}
            desktopsettings.showmouse = d7showcursor.checked;
            desktopsettings.showcad = d7showcad.checked;
            desktopsettings.limitFrameRate = d7limitFrameRate.checked;
            desktopsettings.noMouseRotate = d7noMouseRotate.checked;
            desktopsettings.reverseMouseWheel = d7kvmrmw.checked;
            // ###BEGIN###{DesktopInband}
            desktopsettings.quality = d7bitmapquality.value;
            desktopsettings.scaling = d7bitmapscaling.value;
            // ###END###{DesktopInband}
            try { localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings)); } catch (ex) { }
            applyDesktopSettings();
            // ###BEGIN###{DesktopFocus}
            if (desktopsettings.showfocus == false) { desktop.m.focusmode = 0; idx_deskFocusBtn.value = "All Focus"; }
            // ###END###{DesktopFocus}
            desktop.m.frameRateDelay = (desktopsettings.limitFrameRate == true)?200:0;
            if (desktop.State != 0) { desktop.disconnectCode = 0; desktop.Stop(); setTimeout(connectDesktop, 800); }
        }

        function applyDesktopSettings() {
            // ###BEGIN###{DesktopFocus}
            d7showfocus.checked = desktopsettings.showfocus;
            // ###END###{DesktopFocus}
            d7decimation.value = desktopsettings.decimationMode;
            d7showcursor.checked = desktopsettings.showmouse;
            d7showcad.checked = desktopsettings.showcad;
            d7limitFrameRate.checked = desktopsettings.limitFrameRate;
            d7noMouseRotate.checked = desktopsettings.noMouseRotate;
            d7kvmrmw.checked = desktopsettings.reverseMouseWheel;
            // ###BEGIN###{DesktopInband}
            if (desktopsettings.quality) { d7bitmapquality.value = desktopsettings.quality; }
            if (desktopsettings.scaling) { d7bitmapscaling.value = desktopsettings.scaling; }
            QV('d7softkvmsettings', amtversion >= 12);
            // ###END###{DesktopInband}
            var encflags = desktopsettings.encflags; // Flags: 1 = RLE, 2 = 16bit, 4 = Gray, 8 = ZLib, 16 = 4bit Color

            var x = '';
            if ((amtversion > 15) && (amtsysstate != null) && (amtsysstate['IPS_KVMRedirectionSettingData'] != null) && (amtsysstate['IPS_KVMRedirectionSettingData'].response)) {
                if (!amtsysstate['IPS_KVMRedirectionSettingData'].response['GrayscalePixelFormatSupported']) { encflags = encflags & 11; } // Remove grayscale and lowcolor
                if (!amtsysstate['IPS_KVMRedirectionSettingData'].response['ZlibControlSupported']) { encflags = encflags & 23; } // Remove zlib
                if (amtsysstate['IPS_KVMRedirectionSettingData'].response['GrayscalePixelFormatSupported']) {
                    x += '<option id="d7exm1" value=21>' + "RLE4G, 16 Grays" + '</option>';
                    x += '<option id="d7exm2" value=5>' + "RLE8G, 256 Grays" + '</option>';
                }
                x += '<option value=1>' + "RLE8, 256 Colors" + '</option>';
                x += '<option value=3>' + "RLE16, 64k Colors" + '</option>';
                if (amtsysstate['IPS_KVMRedirectionSettingData'].response['ZlibControlSupported']) {
                    if (amtsysstate['IPS_KVMRedirectionSettingData'].response['GrayscalePixelFormatSupported']) {
                        x += '<option id="d7exm3" value=29>' + "ZRLE4G, Compressed Gray" + '</option>';
                        x += '<option id="d7exm4" value=13>' + "ZRLE8G, Compressed Gray" + '</option>';
                    }
                    x += '<option id="d7exm5" value=9>' + "ZRLE8, Compressed Color" + '</option>';
                    x += '<option id="d7exm6" value=11>' + "ZRLE16, Compressed Color" + '</option>';
                }
                QV('d7decimationspan', amtsysstate['IPS_KVMRedirectionSettingData'].response['InitialDecimationModeForLowRes'] > 0);
            } else {
                encflags = encflags & 3; // Remove gray & zlib flags (4 and 8), keep 1 & 2
                x += '<option value=1>' + "RLE8, 256 Colors" + '</option>';
                x += '<option value=3>' + "RLE16, 64k Colors" + '</option>';
                QV('d7decimationspan', false);
            }
            x += '<option value=0>' + "RAW8, 256 Colors" + '</option>';
            x += '<option value=2>' + "RAW16, 16k Colors" + '</option>';
            QH('idx_d7desktopmode', x);
            idx_d7desktopmode.value = encflags;
            // ###BEGIN###{DesktopFocus}
            QV('idx_deskFocusBtn', desktopsettings.showfocus);
            // ###END###{DesktopFocus}
            QV('id_DeskCAD', desktopsettings.showcad);
        }

        var fullscreen = false;
        var fullscreenonly = false;
        function deskToggleFull(kvmonly) {
            if (xxdialogMode) return;
            if (fullscreenonly == true) {
                // We are in full screen only mode
                console.log('deskToggleFull1', fullscreenonly, urlvars['kvmonly']);
                fullscreenonly = false;
                if (urlvars['kvmonly'] == 1) {
                    //console.log('deskToggleFull2');
                    // It was initiated by a command line switch, exit now.
                    // ###BEGIN###{Mode-NodeWebkit}
                    require('nw.gui').Window.get().close();
                    // ###END###{Mode-NodeWebkit}
                } else {
                    // It was initiated by a menu selection, disconnect now.
                    disconnect();
                }
                return;
            }
            fullscreenonly = kvmonly;
            fullscreen = !fullscreen;
            // ###BEGIN###{!Look-MeshCentral}
            QV('id_topheader', !fullscreen);
            // ###END###{!Look-MeshCentral}
            QV('id_leftbar', !fullscreen);
            QV('id_rdheader', !fullscreen);
            QV('idx_deskFullBtn', !fullscreen);
            QV('idx_deskFullBtn2', fullscreen);
            if (fullscreen) {
                // ###BEGIN###{!Look-MeshCentral}
                QS('id_mainarea').top = 0;
                // ###END###{!Look-MeshCentral}
                QS('id_mainarea').left = 0;
                QS('id_mainarea_pad').padding = 0;
            } else {
                // ###BEGIN###{!Look-MeshCentral}
                // ###BEGIN###{!Look-ISDU}
                QS('id_mainarea').top = '69px';
                // ###END###{!Look-ISDU}
                // ###BEGIN###{Look-ISDU}
                QS('id_mainarea').top = '94px';
                // ###END###{Look-ISDU}
                // ###END###{!Look-MeshCentral}
                QS('id_mainarea').left = '156px';
                QS('id_mainarea_pad').padding = '8px';
            }
            center();
        }

        // ###BEGIN###{DesktopFocus}
        function deskToggleFocus() {
            desktop.m.focusmode = (desktop.m.focusmode + 64) % 192;
            Q('idx_deskFocusBtn').value = ["All Focus", "Small Focus", "Large Focus"][desktop.m.focusmode / 64];
        }
        // ###END###{DesktopFocus}

        // ###BEGIN###{DesktopType}
        // Remote desktop typing
        function deskShowTypeDialog() {
            if (xxdialogMode || desktop.State != 3) return;
            Q('id_DeskType').blur();
            var x = '<div>' + "Enter text and click OK to remotely type it using a US english keyboard. Make sure to place the remote cursor at the correct position before proceeding." + '<div>';
            x += '<textarea id=d2typeText style="margin-top:5px;width:100%;height:184px;resize:none" maxlength=2000></textarea>';
            setDialogMode(11, "Remote Keyboard Entry", 3, showDeskTypeEx, x);
            Q('d2typeText').focus();
        }

        var AmtDeskTypeTimer = null;
        var AmtDeskTypeContent = null;
        var DeskTypeTranslate = { 39: 222, 42: 106, 43: 107, 44: 188, 45: 189, 46: 190, 47: 191, 59: 186, 61: 187, 91: 219, 92: 220, 93: 221, 96: 192, 191: 111 };
        var DeskTypeShiftTranslate = { 33: 49, 34: 222, 35: 51, 36: 52, 37: 53, 38: 55, 40: 57, 41: 48, 58: 186, 60: 188, 62: 190, 63: 191, 64: 50, 94: 54, 95: 189, 106: 56, 107: 187, 123: 219, 124: 220, 125: 221, 126: 192 };
        function showDeskTypeEx() {
            var txt = Q('d2typeText').value, ltxt = Q('d2typeText').value.toUpperCase(), x = [], shift = false;
            //if (desktop.contype == 2) {
                // Intel AMT
                for (var i in txt) { var a = txt.charCodeAt(i); x.push([a, 1], [a, 0]); }
                AmtDeskTypeContent = x;
                AmtDeskTypeTimer = setInterval(function () {
                    var key = AmtDeskTypeContent.shift();
                    if (desktop) { desktop.m.sendkey(key[0], key[1]); }
                    if ((desktop == null) || (AmtDeskTypeContent.length == 0)) { clearInterval(AmtDeskTypeTimer); AmtDeskTypeContent = null; }
                }, 10);
             /*
            } else {
                // MeshAgent
                for (var i in txt) {
                    var a = txt.charCodeAt(i), b = ltxt.charCodeAt(i);
                    if (((a >= 65) && (a <= 90)) || ((a >= 97) && (a <= 122))) {
                        if ((a == b) && (shift == false)) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
                        if ((a != b) && (shift == true)) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // LShift up
                    } else if ((a >= 48) && (a <= 57)) {
                        if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
                    } else if (DeskTypeTranslate[a]) {
                        if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
                        b = DeskTypeTranslate[a];
                    } else if (DeskTypeShiftTranslate[a]) {
                        if (shift == false) { x.push([desktop.m.KeyAction.DOWN, 16]); shift = true; } // LShift down
                        b = DeskTypeShiftTranslate[a];
                    }
                    x.push([desktop.m.KeyAction.DOWN, b], [desktop.m.KeyAction.UP, b]);
                }
                if (shift == true) { x.push([desktop.m.KeyAction.UP, 16]); shift = false; } // Shift up
                desktop.m.SendKeyMsgKC(x);
            }
            */
        }
        // ###END###{DesktopType}

        // Send CTRL-ALT-DEL
        function sendCAD() { if (!Q('id_DeskVO').checked) { desktop.m.sendcad(); } }

        // Special keys
        var deskkeysset = {
            0: [[0xffe7, 1], [0xffe7, 0]], // Win
            1: [[0xffe7, 1], [0xff54, 1], [0xff54, 0], [0xffe7, 0]], // Win+Down
            2: [[0xffe7, 1], [0xff52, 1], [0xff52, 0], [0xffe7, 0]], // Win+Up
            3: [[0xffe7, 1], [0x6c, 1], [0x6c, 0], [0xffe7, 0]], // Win+L
            4: [[0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0]], // Win+M
            5: [[0xffe1, 1], [0xffe7, 1], [0x6d, 1], [0x6d, 0], [0xffe7, 0], [0xffe1, 0]], // Shift+Win+M
            6: [[0xffbe, 1], [0xffbe, 0]], // F1
            7: [[0xffbf, 1], [0xffbf, 0]], // F2
            8: [[0xffc0, 1], [0xffc0, 0]], // F3
            9: [[0xffc1, 1], [0xffc1, 0]], // F4
            10: [[0xffc2, 1], [0xffc2, 0]], // F5
            11: [[0xffc3, 1], [0xffc3, 0]], // F6
            12: [[0xffc4, 1], [0xffc4, 0]], // F7
            13: [[0xffc5, 1], [0xffc5, 0]], // F8
            14: [[0xffc6, 1], [0xffc6, 0]], // F9
            15: [[0xffc7, 1], [0xffc7, 0]], // F10
            16: [[0xffc8, 1], [0xffc8, 0]], // F11
            17: [[0xffc9, 1], [0xffc9, 0]], // F12
            //18: [[0xffe1, 1], [0xffe9, 1], [65, 1], [65, 0], [0xffe9, 0], [0xffe1, 0]]   // Left-Shift + Left-Alt + Print Screen
            19: [[0xffe9, 1], [0xff09, 1], [0xff09, 0], [0xffe9, 0]],  // Alt-Tab
            20: [[0xffe7, 1], [0x72, 1], [0x72, 0], [0xffe7, 0]], // WIN+R
            21: [[0xffe9, 1], [0xffc1, 1], [0xffc1, 0], [0xffe9, 0]], // Alt-F4
            22: [[0xffe3, 1], [0x77, 1], [0x77, 0], [0xffe3, 0]], // Ctrl-W
            23: [[0xffe7, 1], [0xff51, 1], [0xff51, 0], [0xffe7, 0]], // WIN+Left
            24: [[0xffe7, 1], [0xff53, 1], [0xff53, 0], [0xffe7, 0]], // Win+Right
            25: [[0xff0d, 1], [0xff0d, 0]] // Enter
        }

        // Send special keys to the remote side.
        function deskSendKeys() {
            if (Q('id_DeskVO').checked) return;
            var ks = Q('deskkeys').value;
            if (ks != null && deskkeysset[ks] != null && desktop.State != 0) {
                for (var i = 0; i < deskkeysset[ks].length; i++) {
                    desktop.m.sendkey(deskkeysset[ks][i][0], deskkeysset[ks][i][1]);
                }
            }
        }

        // ###BEGIN###{DesktopClipboard}
        // Toggle desktop session recording
        function deskClipboard() {
            if (xxdialogMode || (desktop == null) || (desktop.State != 3)) return;
            var x = '';
            x += "Enter text to send to Intel&reg; AMT clipboard." + '<br />';
            x += '<select id=kvmClipEncoding style=width:100%;margin-top:8px><option value=0>' + "Text Encoding" + '<option value=1>' + "Hex Encoding" + '</select>';
            x += '<textarea id=kvmClipText style=width:100%;height:120px;resize:none;margin-top:8px />';
            setDialogMode(11, "Clipboard", 3, deskClipboardEx, x);
            focusTextBox('kvmClipText');
            if (xxKvmClipEnc != null) { Q('kvmClipEncoding').value = xxKvmClipEnc; }
            if (xxKvmClipVal != null) { Q('kvmClipText').value = xxKvmClipVal; }
        }

        function deskClipboardEx() {
            xxKvmClipEnc = Q('kvmClipEncoding').value;
            xxKvmClipVal = Q('kvmClipText').value;
            if (Q('kvmClipEncoding').value == 0) {
                desktop.m.sendClipboardData(Q('kvmClipText').value.split('\\0').join('\0')); // Text encoded input
            } else {
                desktop.m.sendClipboardData(hex2rstr(Q('kvmClipText').value)); // Hex encoded input
            }
        }
        // ###END###{DesktopClipboard}

        // ###BEGIN###{FileSaver}
        // ###BEGIN###{DesktopRecorder}
        // Toggle desktop session recording
        function deskRecordSession() {
            if ((desktop == null) || (urlvars && urlvars['norecord'])) return;
            if (desktop.m.recordedData == null) {
                // Start recording
                if ((desktop.State === 3) && (desktop.m.StartRecording())) { Q('DeskRecordButton').classList.remove('videoIcon'); Q('DeskRecordButton').classList.add('videoIconRed'); }
            } else {
                // Stop recording
                Q('DeskRecordButton').classList.remove('videoIconRed');
                Q('DeskRecordButton').classList.add('videoIcon');
                var d = new Date(), n = 'AmtDesktopSesion-' + currentcomputer['name'] + '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
                saveAs(data2blob(desktop.m.StopRecording().join('')), n + '.mcrec');
            }
        }
        // ###END###{DesktopRecorder}
        // ###END###{FileSaver}

        // ###BEGIN###{FileSaver}
        // Save the desktop image to file
        function deskSaveImage() {
            if (xxdialogMode || (desktop.State != 3) || (urlvars && urlvars['norecord'])) return;
            var n = 'Desktop', d = new Date();
            if (amtsysstate) { n += '-' + amtsysstate['AMT_GeneralSettings'].response['HostName']; }
            n += '-' + d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);
            // ###BEGIN###{!Mode-NodeWebkit}
            Q('Desk')['toBlob']( function (blob) { saveAs(blob, n + '.jpg'); } );
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var b64image = document.getElementById('Desk').toDataURL('image/png').split(',')[1];
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file');
            chooser.setAttribute('nwsaveas', n + '.png');
            chooser.addEventListener('change', function () { console.log('cc'); require('fs').writeFile(this.value, b64image, 'base64', function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

        // Send special keys
        //function sendSpecialKey() { var k = Q('specialkeylist').value; desktop.m.sendkey(k, 1); desktop.m.sendkey(k, 0); }

        // ###BEGIN###{!DesktopInband}
        function dmousedown(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) desktop.m.mousedown(e); }
        function dmouseup(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) desktop.m.mouseup(e); }
        function dmousemove(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) desktop.m.mousemove(e); }
        function dmousewheel(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) desktop.m.mousewheel(e); }
        // ###END###{!DesktopInband}
        // ###BEGIN###{DesktopInband}
        function dmousedown(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousedown(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousedown(e); } } }
        function dmouseup(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mouseup(e); desktop.m.sendKeepAlive(); } else { desktop.m.mouseup(e); } } }
        function dmousemove(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousemove(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousemove(e); } } }
        function dmousewheel(e) { if (!xxdialogMode && (!Q('id_DeskVO').checked)) { if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null)) { webRtcDesktop.softdesktop.m.mousewheel(e); desktop.m.sendKeepAlive(); } else { desktop.m.mousewheel(e); } } }
        // ###END###{DesktopInband}

        function drotate(x) {
            if (xxdialogMode) return;
            var r = desktop.m.rotation + x;
            desktop.m.setRotation(r);
            // ###BEGIN###{DesktopInband}
            if ((webRtcDesktop != null) && (webRtcDesktop.softdesktop != null) && (webRtcDesktop.softdesktop.m != null)) {
                webRtcDesktop.softdesktop.m.setRotation(r); }
            // ###END###{DesktopInband}
            center();
        }

        // ###BEGIN###{DesktopInbandFiles}
        
        // 
        // Remote Files
        //

        var p24files = null;
        var p24filetree = null;
        var p24targetpath = null;
        var p24filetreelocation = [];

        function onFilesControlData(data) {
            if ((data.length > 0) && (data.charCodeAt(0) != 123)) { p24gotDownloadBinaryData(data); return; }
            data = JSON.parse(data);
            if (data.action == 'download') { p24gotDownloadCommand(data); return; }
            if (data.action == 'upload') { p24gotUploadData(data); return; }
            if (data.action == 'pong') { return; }
            data.path = data.path.replace(/\//g, '\\');
            if ((p24filetree != null) && (data.path == p24filetree.path)) {
                // This is an update to the same folder
                var checkedNames = p24getCheckedNames();
                p24filetree = data;
                p24updateFiles(checkedNames);
            } else {
                // Make both paths use the same seperator not start with /
                var x1 = data.path.split('/').join('\\');
                var x2 = p24targetpath.split('/').join('\\');
                while ((x1.length > 0) && (x1[0] == '\\')) { x1 = x1.substring(1); }
                while ((x2.length > 0) && (x2[0] == '\\')) { x2 = x2.substring(1); }
                if ((x1 == x2) || ((data.path == '\\') && (p24targetpath == ''))) {
                    // This is a different folder
                    p24filetree = data;
                    p24updateFiles();
                }
            }
        }

        function p24getCheckedNames() {
            // Save all existing checked boxes
            var checkedNames = [], checkboxes = document.getElementsByName('fd');
            for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedNames.push(p24filetree.dir[checkboxes[i].value].n) }; }
            return checkedNames;
        }

        //var p24oldlinkpath = null;
        function p24updateFiles(checkedNames) {
            var html1 = '', html2 = '', displayPath = '<a style=cursor:pointer onclick=p24folderup(0)>' + "Root" + '</a>', fullPath = 'Root';

            // Work on parsing the file path
            var x = p24filetree.path.split('\\');
            p24filetreelocation = [];
            for (var i in x) { if (x[i] != '') { p24filetreelocation.push(x[i]); } } // Remove empty spaces
            for (var i in p24filetreelocation) { displayPath += ' / <a style=cursor:pointer onclick=p24folderup(' + (parseInt(i) + 1) + ')>' + p24filetreelocation[i] + '</a>' } // Setup the path we display
            var newlinkpath = p24filetreelocation.join('/');

            // Sort the files
            var filetreexx = p24sort_files(p24filetree.dir);

            // Display all files and folders at this location
            for (var i in filetreexx) {
                // Figure out the name and shortname
                var f = filetreexx[i], name = f.n, shortname;
                shortname = name;
                if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + "..." + '</span>'; } else { shortname = EscapeHtml(name); }
                name = EscapeHtml(name);

                // Figure out the date
                var fdatestr = '';
                if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + '/' + (fdate.getDate()) + '/' + fdate.getFullYear() + ' ' + fdate.toLocaleTimeString() + '&nbsp;'; }

                // Figure out the size
                var fsize = '';
                if (f.s != null) { fsize = getFileSizeStr(f.s); }

                var h = '';
                if (f.t < 3) {
                    var right = '', title = '';
                    h = '<div class=filelist file=999><input file=999 style=float:left name=fd class=fcb type=checkbox onchange=p24setActions() value="' + f.nx + '">&nbsp;<span style=float:right title=\"' + title + '\">' + right + '</span><span><div class=fileIcon' + f.t + '></div><a style=cursor:pointer onclick=p24folderset(\"' + encodeURIComponent(f.nx) + '\")>' + shortname + '</a></span></div>';
                } else {
                    var link = shortname;
                    if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" style=cursor:pointer onclick=\'p24downloadfile("' + encodeURIComponent(newlinkpath + '/' + name) + '","' + encodeURIComponent(name) + '",' + f.s + ')\'>' + shortname + '</a>'; }
                    h = '<div class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p24setActions() value="' + f.nx + '">&nbsp;<span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
                }

                if (f.t < 3) { html1 += h; } else { html2 += h; }
            }

            // Display the files and path
            QH('p24files', html1 + html2);
            QH('p24currentpath', displayPath);
            QE('p24FolderUp', p24filetreelocation.length != 0);

            // Re-check all boxes if needed using names
            if (checkedNames != null) { var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkedNames.indexOf(p24filetree.dir[checkboxes[i].value].n) >= 0) { checkboxes[i].checked = true; } } }

            // Update the actions buttons
            p24setActions();
        }

        function p24folderset(x) {
            p24targetpath = joinPaths(p24filetree.path, p24filetree.dir[x].n).split('\\').join('/');
            p24files.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: p24targetpath }));
        }

        function p24folderup(x) {
            if (x == null) { p24filetreelocation.pop(); } else { while (p24filetreelocation.length > x) { p24filetreelocation.pop(); } }
            p24targetpath = p24filetreelocation.join('/');
            p24files.sendCtrlMsg(JSON.stringify({ action: 'ls', reqid: 1, path: p24targetpath }));
        }

        var p24sortorder;
        function p24sort_filename(a, b) { if (a.ln > b.ln) return (1 * p24sortorder); if (a.ln < b.ln) return (-1 * p24sortorder); return 0; }
        function p24sort_timestamp(a, b) { if (a.d > b.d) return (1 * p24sortorder); if (a.d < b.d) return (-1 * p24sortorder); return 0; }
        function p24sort_bysize(a, b) { if (a.s == b.s) return p24sort_filename(a, b); return (((a.s - b.s)) * p24sortorder); }

        function p24sort_files(files) {
            var r = [], sortselection = Q('p24sortdropdown').value;
            for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
            p24sortorder = 1;
            if (sortselection > 3) { p24sortorder = -1; sortselection -= 3; }
            if (sortselection == 1) { r.sort(p24sort_filename); }
            else if (sortselection == 2) { r.sort(p24sort_bysize); }
            else if (sortselection == 3) { r.sort(p24sort_timestamp); }
            return r;
        }

        function p24setActions() {
            if (p24filetree == null) {
                QE('p24DeleteFileButton', false);
                QE('p24NewFolderButton', false);
                QE('p24UploadButton', false);
                QE('p24RenameFileButton', false);
                QE('p24SelectAllButton', false);
                Q('p24SelectAllButton').value = "Select All";
                QE('p24RefreshButton', false);
                QE('p24CutButton', false);
                QE('p24CopyButton', false);
                QE('p24PasteButton', false);
            } else {
                var cc = p24getFileSelCount(), tc = p24getFileCount(), sfc = p24getFileSelCount(false); // In order: number of entires selected, number of total entries, number of selected entires that are files (not folders)
                var winAgent = (webRtcDesktop.platform == 'win32');
                QE('p24DeleteFileButton', (cc > 0) && ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24NewFolderButton', ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24UploadButton', ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24RenameFileButton', (cc == 1) && ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24SelectAllButton', tc > 0);
                Q('p24SelectAllButton').value = (cc > 0 ? "Select None" : "Select All");
                QE('p24RefreshButton', true);
                QE('p24CutButton', (cc > 0) && (cc == sfc) && ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24CopyButton', (cc > 0) && (cc == sfc) && ((p24filetreelocation.length > 0) || (winAgent == false)));
                QE('p24PasteButton', ((p24filetreelocation.length > 0) || (winAgent == false)) && ((p24clipboard != null) && (p24clipboard.length > 0)));
            }
        }

        function p24getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
        function p24getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); return checkboxes.length; }
        function p24selectallfile() { var nv = (p24getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p24setActions(); }
        function p24createfolder() { setDialogMode(11, "New Folder", 3, p24createfolderEx, '<input type=text id=p24renameinput maxlength=64 onkeyup=p24fileNameCheck(event) style=width:100% />'); focusTextBox('p24renameinput'); p24fileNameCheck(); }
        function p24createfolderEx() { p24files.sendCtrlMsg(JSON.stringify({ action: 'mkdir', reqid: 1, path: p24filetreelocation.join('/') + '/' + Q('p24renameinput').value })); p24folderup(999); }
        function p24deletefile() { var cc = p24getFileSelCount(); setDialogMode(11, "Delete", 3, p24deletefileEx, (cc > 1) ? ('Delete ' + cc + ' selected items?') : ('Delete selected item?')); }
        function p24deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(p24filetree.dir[checkboxes[i].value].n); } } p24files.sendCtrlMsg(JSON.stringify({ action: 'rm', reqid: 1, path: p24filetreelocation.join('/'), delfiles: delfiles })); p24folderup(999); }
        function p24renamefile() { var renamefile, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = p24filetree.dir[checkboxes[i].value].n; } } setDialogMode(11, "Rename", 3, p24renamefileEx, '<input type=text id=p24renameinput maxlength=64 onkeyup=p24fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p24filetreelocation.join('/'), oldname: renamefile }); focusTextBox('p24renameinput'); p24fileNameCheck(); }
        function p24renamefileEx(b, t) { t.newname = Q('p24renameinput').value; p24files.sendCtrlMsg(JSON.stringify(t)); p24folderup(999); }
        function p24fileNameCheck(e) { var x = isFilenameValid(Q('p24renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 24)) { dialogclose(1); } }
        function p24uploadFile() { setDialogMode(11, "Upload File", 3, p24uploadFileEx, '<input type=file name=files id=p24uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p24uploadinput\')" />'); updateUploadDialogOk('p24uploadinput'); }
        function p24uploadFileEx() { p24doUploadFiles(Q('p24uploadinput').files); }
        function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }

        var p24clipboard = null, p24clipboardFolder = null, p24clipboardCut = 0;
        function p24copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p24clipboard = []; p24clipboardCut = cut, p24clipboardFolder = p24targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p24clipboard.push(p24filetree.dir[checkboxes[i].value].n); } } p24updateClipview(); }
        function p24pasteFile() { var x = ''; if ((p24clipboard != null) && (p24clipboard.length > 0)) { x = 'Confim ' + (p24clipboardCut == 0 ? 'copy' : 'move') + ' of ' + p24clipboard.length + ' entrie' + ((p24clipboard.length > 1) ? 's' : '') + ' to this location?' } setDialogMode(11, "Paste", 3, p24pasteFileEx, x); }
        function p24pasteFileEx() { p24files.sendCtrlMsg(JSON.stringify({ action: (p24clipboardCut == 0 ? 'copy' : 'move'), reqid: 1, scpath: p24clipboardFolder, dspath: p24targetpath, names: p24clipboard })); p24folderup(999); if (p24clipboardCut == 1) { p24clipboard = null, p24clipboardFolder = null, p24clipboardCut = 0; p24updateClipview(); } }
        function p24updateClipview() { var x = ''; if ((p24clipboard != null) && (p24clipboard.length > 0)) { x = 'Holding ' + p24clipboard.length + ' entrie' + ((p24clipboard.length > 1) ? 's' : '') + ' for ' + (p24clipboardCut == 0 ? 'copy' : 'move') + ', <a onclick=p24clearClip() style=cursor:pointer>Clear</a>.' } QH('p24bottomstatus', x); p24setActions(); }
        function p24clearClip() { p24clipboard = null; p24clipboardFolder = null; p24clipboardCut = 0; p24updateClipview(); }

        function p24fileDragDrop(e) {
            haltEvent(e);
            QV('p24bigfail', false);
            QV('p24bigok', false);
            if (e.dataTransfer == null || e.dataTransfer.files.length == 0 || p24filetree == null) return;
            if ((p24filetreelocation.length == 0) && (webRtcDesktop.platform == 'win32')) return // If this is Windows, do not accept files in the root folder
            p24doUploadFiles(e.dataTransfer.files);
        }

        var p24dragtimer = null;
        function p24fileDragOver(e) {
            haltEvent(e);
            if (p24dragtimer != null) { clearTimeout(p24dragtimer); p24dragtimer = null; }
            var ac = (p24filetree != null); // Set to true if we can accept the file
            if ((p24filetreelocation.length == 0) && (webRtcDesktop.platform == 'win32')) { ac = false; } // If this is Windows, do not accept files in the root folder
            QV('p24bigok', ac);
            QV('p24bigfail', !ac);
        }

        function p24fileDragLeave(e) {
            haltEvent(e);
            if (e.target.id != "p24filetable") {
                QV('p24bigfail', false);
                QV('p24bigok', false);
            } else {
                p24dragtimer = setTimeout(function () { QV('p24bigfail', false); QV('p24bigok', false); p24dragtimer = null; }, 200);
            }
        }

        function getFileSizeStr(size) { if (size == 1) return "1 byte"; return format("{0} bytes", size); }
        function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
        var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
        function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }


        //
        // FILES DOWNLOAD
        //

        var downloadFile; // Global state for file download

        // Called by the html page to start a download, arguments are: path, file name and file size.
        function p24downloadfile(x, y, z) {
            if (xxdialogMode || downloadFile || !p24files) return;
            downloadFile = { path: decodeURIComponent(x), file: decodeURIComponent(y), size: z, tsize: 0, data: '', state: 0, id: Math.random() }
            //console.log('p24downloadFileCancel', downloadFile);
            p24files.sendCtrlMsg(JSON.stringify({ action: 'download', sub: 'start', id: downloadFile.id, path: downloadFile.path }));
            setDialogMode(11, "Download File", 10, p24downloadFileCancel, '<div>' + downloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
        }

        // Called by the html page to cancel the download
        function p24downloadFileCancel() { if (downloadFile != null) { setDialogMode(0); if (p24files != null) { p24files.sendCtrlMsg(JSON.stringify({ action: 'download', sub: 'cancel', id: downloadFile.id })); } downloadFile = null; } }

        // Called by the transport when download control command is received
        function p24gotDownloadCommand(cmd) {
            //console.log('p24gotDownloadCommand', cmd);
            if ((downloadFile == null) || (cmd.id != downloadFile.id)) return;
            if (cmd.sub == 'start') { downloadFile.state = 1; p24files.sendCtrlMsg(JSON.stringify({ action: 'download', sub: 'startack', id: downloadFile.id })); }
            else if (cmd.sub == 'cancel') { downloadFile = null; setDialogMode(0); }
        }

        // Called by the transport when binary data is received
        function p24gotDownloadBinaryData(data) {
            if (!downloadFile || downloadFile.state == 0) return;
            try { data = atob(data); } catch (ex) { return; }
            if ((data == null) || (data.length < 4)) return;
            if (data.length > 4) {
                downloadFile.tsize += data.length - 4; // Add to the total bytes received
                downloadFile.data += data.substring(4); // Append the data, decode Base64
                Q('d2progressBar').value = downloadFile.tsize; // Change the progress bar
            }
            if ((ReadInt(data, 0) & 1) != 0) { // Check end flag
                saveAs(data2blob(downloadFile.data), downloadFile.file); downloadFile = null; setDialogMode(0); // Save the file
            } else {
                p24files.sendCtrlMsg(JSON.stringify({ action: 'download', sub: 'ack', id: downloadFile.id })); // Send the ACK
            }
        }

        //
        // FILES UPLOAD
        //

        var uploadFile;

        function p24doUploadFiles(files) {
            if (xxdialogMode) return;
            uploadFile = { xpath: p24filetreelocation.join('/'), xfiles: files, xfilePtr: -1 };
            setDialogMode(11, "Upload File", 10, p24uploadFileCancel, '<div id=p24dfileName>' + "Setting up..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />', 99);
            p24uploadNextFile();
        }

        // Push the next file
        function p24uploadNextFile() {
            uploadFile.xfilePtr++;
            if (uploadFile.xfiles.length > uploadFile.xfilePtr) {
                uploadFile.xptr = 0;
                var file = uploadFile.xfiles[uploadFile.xfilePtr];
                QH('p24dfileName', file.name);
                Q('d2progressBar').max = file.size;
                Q('d2progressBar').value = 0;
                uploadFile.xreader = new FileReader();
                uploadFile.xreader.onload = function () {
                    uploadFile.xdata = uploadFile.xreader.result;
                    p24files.sendCtrlMsg(JSON.stringify({ action: 'upload', sub: 'start', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength }));
                };
                uploadFile.xreader.onerror = function () { p24uploadNextFile(); }
                uploadFile.xreader.readAsArrayBuffer(file);
            } else {
                p24uploadFileCancel();
                p24folderup(9999); // Refresh the file view
            }
        }

        // Used to cancel the entire transfer, close the upload dialog box
        function p24uploadFileCancel(button, tag) {
            if (uploadFile != null) {
                uploadFile = null;
                setDialogMode(0);
                if ((tag == 99) && (p24files != null)) { p24files.sendCtrlMsg(JSON.stringify({ action: 'upload', sub: 'cancel' })); }
            }
        }

        // Receive upload ack from the mesh agent, use this to keep sending more data
        function p24gotUploadData(cmd) {
            if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
            if (cmd.sub == 'start') {
                p24uploadNextPart(false);
                for (var i = 0; i < 8; i++) { p24uploadNextPart(true); } // Send 8 more blocks of 4 k to full the websocket.
            } else if (cmd.sub == 'ack') {
                p24uploadNextPart(false);
            } else if (cmd.sub == 'error') {
                p24uploadFileCancel();
            }
        }

        function ab2str(buf) { return String.fromCharCode.apply(null, new Uint8Array(buf)); }

        // Push the next part of the file into the websocket. If dataPriming is true, push more data only if it's not the last block of the file.
        function p24uploadNextPart(dataPriming) {
            var data = uploadFile.xdata, start = uploadFile.xptr, end = uploadFile.xptr + 4096;
            if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
            if (start == data.byteLength) {
                p24uploadNextFile();
            } else {
                p24files.sendCtrlMsg(btoa(IntToStr((end != data.byteLength) ? 0x01000000 : 0x01000001) + ab2str(data.slice(start, end))));
                uploadFile.xptr = end;
                Q('d2progressBar').value = end;
            }
        }

        // ###END###{DesktopInbandFiles}
        // ###END###{Desktop}

        //
        // Remote IDER
        //

        // ###BEGIN###{IDER}

        var ider;
        var iderCodeBlock;
        var iderTimer;

        // ###BEGIN###{IDER-IMRSDK}
        function iderStartIMR() {
            // Setup the IDER session (NodeJS with IMRSDK.dll)
            iderStop();
            ider = CreateAmtRemoteIderIMR();
            if (ider == null) return;
            ider.digestRealmMatch = wsstack.comm.digestRealm;
            ider.onStateChanged = onIderStateChange;
            ider.m.onDialogPrompt = onIderDialogPrompt;

            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                ider.m.Start(currentcomputer._id, 16992, 'x', 'x', 0, wsstack.comm, meshCentralServer);
            } else {
                // ###END###{MeshServerConnect}
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
                ider.m.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls'], amtstack.wsman.comm.xtlsCertificate, wsstack.comm.xtlsoptions);
                // ###BEGIN###{MeshServerConnect}
            }
            // ###END###{MeshServerConnect}

            QV('IDERDiskMapButton', false); // Hide the disk heat map button since it's not supported.
        }

        function onIderSourceChange() {
            var sel = Q('storagesourceoption').value;
            QV('iderisofile', (sel & 1) == 0);
            QV('iderimgfile', (sel & 2) == 0);
            QV('iderisodrive', (sel & 1) != 0);
            QV('iderimgdrive', (sel & 2) != 0);
        }
        // ###END###{IDER-IMRSDK}

        function iderStart(e) {
            if (xxdialogMode) return;
            // ###BEGIN###{IDER-IMRSDK}
            if ((e.shiftKey != true) && (require('os').platform() == 'win32')) { iderStartIMR(); return; }
            // ###END###{IDER-IMRSDK}

            // Setup the IDER session (WebSocket)
            var x = '<div>' + "Mount disk images on a Intel&reg; AMT computer - Experimental." + '</div><br />';
            x += '<div style=height:26px><input id=floppyImageInput type=file style=float:right;width:250px accept=".img"><div>' + NoBreak("Floppy (.img)") + '</div></div>';
            x += '<div style=height:26px><input id=cdromImageInput type=file style=float:right;width:250px accept=".iso"><div>' + NoBreak("CDROM (.iso)") + '</div></div>';
            x += '<div style=height:26px><select id=iderStartType style=float:right;width:250px><option value=0>' + "On next boot" + '<option value=1>' + "Graceful" + '<option value=2>' + "Immediate" + '</select><div>' + "Session Start" + '</div></div>';
            setDialogMode(11, "Storage Redirection", 3, iderStart2, x);
            var iderurl = null;
            try { iderurl = localStorage.getItem('iderurl'); } catch (ex) { }
            if (iderurl) { Q('storageserverurl').value = iderurl.substring(1, iderurl.length - 1); }
        }

        function iderStart2() {
            // Check the files
            if ((Q('floppyImageInput').files.length != 1) && (Q('cdromImageInput').files.length != 1)) { messagebox("Storage Redirection Error", "At least one disk image file must be selected."); return; }
            if ((Q('floppyImageInput').files.length == 1) && ((Q('floppyImageInput').files[0].size % 512) != 0)) { messagebox("Storage Redirection Error", "Invalid .img file."); return; }
            if ((Q('cdromImageInput').files.length == 1) && ((Q('cdromImageInput').files[0].size % 2048) != 0)) { messagebox("Storage Redirection Error", "Invalid .iso file."); return; }

            // Fetch the files
            var floppy = null, cdrom = null;
            if (Q('floppyImageInput').files.length == 1) { floppy = Q('floppyImageInput').files[0]; }
            if (Q('cdromImageInput').files.length == 1) { cdrom = Q('cdromImageInput').files[0]; }
            if ((floppy != null) || (cdrom != null)) { iderStart3(floppy, cdrom, Q('iderStartType').value); }
        }

        function iderStart3(floppy, cdrom, iderStart) {
            // Setup the IDER session
            iderStop();
            ider = CreateAmtRedirect(CreateAmtRemoteIder());
            ider.onStateChanged = onIderStateChange;
            ider.m.floppy = floppy;
            ider.m.cdrom = cdrom;
            ider.m.iderStart = iderStart;
            // ###BEGIN###{ComputerSelector}
            ider.digestRealmMatch = wsstack.comm.digestRealm;
            // ###END###{ComputerSelector}
            // ###BEGIN###{IDERStats}
            ider.m.sectorStats = iderSectorStats;
            // ###END###{IDERStats}

            // ###BEGIN###{Mode-MeshCentral2}
            ider.tlsv1only = amtstack.wsman.comm.tlsv1only;
            ider.Start(currentMeshNode._id, 16994, '*', '*', 0);
            // ###END###{Mode-MeshCentral2}
            // ###BEGIN###{!Mode-MeshCentral2}
            // ###BEGIN###{Mode-Firmware}
            ider.Start();
            // ###END###{Mode-Firmware}
            // ###BEGIN###{!Mode-Firmware}
            ider.tlsv1only = amtstack.wsman.comm.tlsv1only;
            // ###BEGIN###{MeshServerConnect}
            if (meshCentralServer != null) {
                desktop.Start(currentcomputer._id, 0, 'x', 'x', 0, wsstack.comm, meshCentralServer);
            } else {
            // ###END###{MeshServerConnect}
                var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
                // ###BEGIN###{!Mode-NodeWebkit}
                ider.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls']);
                // ###END###{!Mode-NodeWebkit}
                // ###BEGIN###{Mode-NodeWebkit}
                ider.Start(ports.host, ports.redir, amtstack.wsman.comm.user, amtstack.wsman.comm.pass, currentcomputer['tls'], wsstack.comm.getPeerCertificateFingerprint(), wsstack.comm.xtlsoptions);
                // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{MeshServerConnect}
            }
            // ###END###{MeshServerConnect}
            // ###END###{!Mode-Firmware}
            // ###END###{!Mode-MeshCentral2}

            QV('IDERDiskMapButton', true); // Show the disk heat map button since it is supported.
        }

        function iderStop() {
            // Stop the IDER session
            if (ider) { ider.m.Stop(); ider.onStateChanged = null; ider.m.onDialogPrompt = null; delete ider; }
            if (iderTimer) { clearInterval(iderTimer); delete iderTimer; }
            // ###BEGIN###{IDERStats}
            iderToggleDiskMap(false);
            // ###END###{IDERStats}
        }

        function onIderStateChange(stack, state) {
            QE('idx_IDER1', state != 3);
            QE('idx_IDER2', state != 3);
            // ###BEGIN###{Mode-MeshCentral2}
            QE('idx_SIDER1', state != 3);
            QE('idx_SIDER2', state != 3);
            // ###END###{Mode-MeshCentral2}

            QV('id_iderstatus', state == 3); center();
            if (state == 3) {
                if (!urlvars['norefresh']) { iderTimer = setInterval(onIderTimer, 500); }
                onIderTimer();
            } else {
                if (iderTimer) { clearInterval(iderTimer); delete iderTimer; }
            }
        }

        function onIderTimer() {
            if (ider.m.Update) { ider.m.Update(); }
            if (ider.m.bytesFromAmt == -1) { iderStop(); } else { QH('id_iderstatusstr', '<b>' + (ider.m.server?"Server ":'') + "IDE-R Session</b>, Connected, " + ider.m.bytesFromAmt + " in, " + ider.m.bytesToAmt + " out."); }
        }

        // ###BEGIN###{IDERStats}
        var heatMapWidth = 600;
        var heatMapDividor = {};
        function iderSectorStats(mode, dev, total, start, len) {
            var canvas = dev ? Q('cdromHeatMapCanvas') : Q('floppyHeatMapCanvas');
            var ctx = canvas.getContext('2d');
            if (mode == 0) {
                heatMapDividor[dev] = 1;
                if (total > 0) { while ((total / heatMapDividor[dev]) > 8000) { heatMapDividor[dev] *= 2; } }
                if (dev) {
                    QV('cdromHeatMap', total)
                    QH('cdromHeatMapText', format("<b>CDROM</b>, blocks are {0} bytes.", (2048 * heatMapDividor[dev])));
                } else {
                    QV('floppyHeatMap', total);
                    QH('floppyHeatMapText', format("<b>Floppy</b>, blocks are {0} bytes.", (512 * heatMapDividor[dev])));
                }
            }
            var dividor = heatMapDividor[dev];
            total = total / dividor;
            start = start / dividor;
            len = len / dividor;
            var heatMapScale = 6;
            if (mode == 0) {
                canvas.height = ((Math.floor(total / (heatMapWidth / heatMapScale)) + ((total % heatMapWidth) ? 1 : 0)) * heatMapScale);
                ctx.fillStyle = 'rgba(225,250,225,1)';
                ctx.fillRect(0, 0, heatMapWidth, Math.floor(total / (heatMapWidth / heatMapScale)) * heatMapScale);
                if (total % heatMapWidth) { ctx.fillRect(0, Math.floor(total / (heatMapWidth / heatMapScale)) * heatMapScale, (total % (heatMapWidth / heatMapScale)) * heatMapScale, heatMapScale); }
                ctx.fillStyle = 'rgba(0,0,0,0.3)';
            } else {
                for (var i = start; i < start + len; i++) { sectorHeat(ctx, i, heatMapScale, dividor); }
            }
        }

        function sectorHeat(ctx, sector, scale, dividor) {
            ctx.fillRect((sector % (heatMapWidth / scale)) * scale, Math.floor(sector / (heatMapWidth / scale)) * scale, scale, scale);
        }

        function iderToggleDiskMap(x) {
            var visible = (QS('iderHeatmap').display != 'none');
            if (x == null) { x = !visible; }
            if (xxdialogMode) { x = false; }
            QS('iderHeatmap').display = x ? '' : 'none';
        }
        // ###END###{IDERStats}

        function onIderDialogPrompt(sender, args, buttons) {
            if (iderCodeBlock) { document.body.removeChild(iderCodeBlock); delete iderCodeBlock; }
            if (args['js']) { var JS = document.createElement('script'); JS.text = args['js']; iderCodeBlock = document.body.appendChild(JS); }
            setDialogMode(11, "Storage Redirection", buttons ? buttons : 3, onIderDialogPromptOk, args['html']);
        }

        function onIderDialogPromptOk(button) {
            if (button == 1) {
                // ###BEGIN###{!Mode-NodeWebkit}
                if (window['iderServerCall']) { ider.m.dialogPrompt(window['iderServerCall']()); } else { ider.m.dialogPrompt(); }
                // ###END###{!Mode-NodeWebkit}
                // ###BEGIN###{Mode-NodeWebkit}
                ider.m.dialogPrompt(iderUserConsent);
                // ###END###{Mode-NodeWebkit}
            } else {
                iderStop();
            }
        }

        // ###BEGIN###{Mode-NodeWebkit}
        var restartIderFunction;
        function iderUserConsent(func) {
            restartIderFunction = func;
            amtstack.IPS_OptInService_StartOptIn(iderUserConsent2, 0, 1);
        }

        function iderUserConsent2(stack, name, response, status) {
            if (errcheck(status, stack)) return;
            //console.log("powerActionResponseC1(" + name + "," + response + "," + status + ")");
            if (response.Body['ReturnValue'] != 0) {
                messagebox("User Consent Error", response.Body.ReturnValueStr.replace(/_/g, ' '));
            } else {
                d6ConsentText.value = ''; // Reset user consent code to empty
                setDialogMode(6, "User Consent", 11, iderUserConsent3);
                checkConsentDisplay();
                consentChanged();
            }
        }

        function iderUserConsent3() {
            //console.log('IPS_OptInService_SendOptInCode()');
            amtstack.IPS_OptInService_SendOptInCode(d6ConsentText.value, iderUserConsent4, 0, 1);
        }

        function iderUserConsent4(stack, name, response, status) {
            if (errcheck(status, stack)) return;
            //console.log("powerActionResponseC2(" + name + "," + response + "," + status + ")");
            if (response.Body['ReturnValue'] != 0) {
                messagebox("User Consent Error", response.Body.ReturnValueStr.replace('_',' '));
            } else {
                restartIderFunction();
            }
        }
        // ###END###{Mode-NodeWebkit}

        // ###BEGIN###{Mode-MeshCentral2}

        // Server-side IDER
        function iderServerStart() {
            if (xxdialogMode) return;

            // Setup the IDER session (NodeJS)
            iderStop();
            ider = CreateAmtRemoteServerIder();
            if (ider == null) return;
            ider.onStateChanged = onIderStateChange;
            ider.m.sectorStats = iderSectorStats;
            ider.m.onDialogPrompt = onIderDialogPrompt;
            ider.tlsv1only = amtstack.wsman.comm.tlsv1only;
            ider.Start(currentMeshNode._id, 16994, '*', '*', 0);
        }

        // ###END###{Mode-MeshCentral2}

        // ###END###{IDER}

        // ###BEGIN###{RemoteAccess}

        //
        // Remote Access
        //

        var xxRemoteAccess = null;
        var xxEnvironementDetection = null;
        var xxCiraServers = null;
        var xxUserInitiatedCira = null;
        var xxUserInitiatedEnabledState = { 32768: "Disabled", 32769: "BIOS enabled", 32770: "OS enable", 32771: "BIOS & OS enabled" };
        var xxRemoteAccessCredentiaLinks = null;
        var xxMPSUserPass = null;
        var xxPolicies = null;

        function PullRemoteAccess() {
            // We only deal with remote access starting with Intel AMT 6 and beyond
            // ###BEGIN###{Certificates}
            var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword'];
            // ###END###{Certificates}
            // ###BEGIN###{!Certificates}
            var requests = ['*AMT_EnvironmentDetectionSettingData', 'AMT_ManagementPresenceRemoteSAP', 'AMT_RemoteAccessCredentialContext', 'AMT_RemoteAccessPolicyAppliesToMPS', 'AMT_RemoteAccessPolicyRule', '*AMT_UserInitiatedConnectionService', 'AMT_MPSUsernamePassword', 'AMT_PublicKeyCertificate'];
            // ###END###{!Certificates}
            if (amtversion > 11) { requests.push('*IPS_HTTPProxyService', 'IPS_HTTPProxyAccessPoint'); }
            amtstack.BatchEnum(null, requests, processRemote1);
        }

        function processRemote1(stack, name, responses, status) {
            if ((amtversion > 11) && (status == 400)) {
                // Check if only the HTTP proxy objects failed
                status = 200;
                if (responses['IPS_HTTPProxyAccessPoint'].status == 400) { delete responses['IPS_HTTPProxyAccessPoint']; }
                if (responses['IPS_HTTPProxyService'].status == 400) { delete responses['IPS_HTTPProxyService']; }
                for (var i in responses) { if (responses[i].status != 200) { status = responses[i].status; } }
            }
            if (status == 400) return;
            if ((errcheck(status, stack)) || (responses['AMT_UserInitiatedConnectionService'] == undefined || responses['AMT_UserInitiatedConnectionService'].response == undefined)) return;
            QV('go17', true); // Remote Access
            xxRemoteAccess = responses;
            xxEnvironementDetection = responses['AMT_EnvironmentDetectionSettingData'].response;
            xxEnvironementDetection['DetectionStrings'] = MakeToArray(xxEnvironementDetection['DetectionStrings']);
            xxCiraServers = responses['AMT_ManagementPresenceRemoteSAP'].responses;
            xxUserInitiatedCira = responses['AMT_UserInitiatedConnectionService'].response;
            xxRemoteAccessCredentiaLinks = responses['AMT_RemoteAccessCredentialContext'].responses;
            xxMPSUserPass = responses['AMT_MPSUsernamePassword'].responses;

            // Figure out policies attached to servers. Create a policy type to server table.
            xxPolicies = { 'User': [], 'Alert': [], 'Periodic': [] };
            for (var i in responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses) {
                var policy = responses['AMT_RemoteAccessPolicyAppliesToMPS'].responses[i];
                var server = Clone(getItem(xxCiraServers, 'Name', getItem(policy['ManagedElement']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'Name')['Value']));
                server.MpsType = policy['MpsType']; // MpsType was added in Intel AMT 11.6
                var ptype = (getItem(policy['PolicySet']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'PolicyRuleName')['Value']).split(' ')[0];
                xxPolicies[ptype].push(server);
            }

            updateRemoteAccess();
        }

        function updateRemoteAccess() {
            if (xxEnvironementDetection == null) return;
            var x = '', e = "Disabled", ciraProxySupport = (xxRemoteAccess['IPS_HTTPProxyService'] && xxRemoteAccess['IPS_HTTPProxyAccessPoint']);
            if (xxEnvironementDetection['DetectionStrings'] && xxEnvironementDetection['DetectionStrings'].length > 0) { e = "Enabled, " + xxEnvironementDetection['DetectionStrings'].length + ' ' + (xxEnvironementDetection['DetectionStrings'].length > 1?'domains':'domain'); }

            // General settings
            x += TableStart();
            x += TableEntry("Environment detection", addLink(e, 'editEnvironmentDetection()'));
            x += TableEntry("User initiation options", addLinkConditional(xxUserInitiatedEnabledState[xxUserInitiatedCira['EnabledState']], 'editUserInitiatedCira()', xxAccountAdminName));
            var y = ('<i>' + "None" + '</i>');
            if (xxPolicies['User'].length > 0) { y = ''; for (var i in xxPolicies['User']) { if (y.length > 0) y += ', '; y += xxPolicies['User'][i]['AccessInfo']; if (xxPolicies['User'][i].MpsType == 1) { y += ' (CILA)'; } } }
            x += TableEntry("User initiated connection", addLinkConditional(y, 'editMpsPolicy("User")', xxAccountAdminName));
            var y = ('<i>' + "None" + '</i>');
            if (xxPolicies['Alert'].length > 0) { y = ''; for (var i in xxPolicies['Alert']) { if (y.length > 0) y += ', '; y += xxPolicies['Alert'][i]['AccessInfo']; if (xxPolicies['Alert'][i].MpsType == 1) { y += ' (CILA)'; } } }
            x += TableEntry("Alert initiated connection", addLinkConditional(y, 'editMpsPolicy("Alert")', xxAccountAdminName));
            var y = ('<i>' + "None" + '</i>');
            if (xxPolicies['Periodic'].length > 0) { y = ''; for (var i in xxPolicies['Periodic']) { if (y.length > 0) y += ', '; y += xxPolicies['Periodic'][i]['AccessInfo']; if (xxPolicies['Periodic'][i].MpsType == 1) { y += ' (CILA)'; } } }
            var periodicPolicy = getItem(xxRemoteAccess['AMT_RemoteAccessPolicyRule'].responses, "PolicyRuleName", "Periodic");
            if (periodicPolicy) {
                var exdata = atob(periodicPolicy['ExtendedData']);
                if (ReadInt(exdata, 0) == 0) { y += format(", each {0} seconds", ReadInt(exdata, 4)); }
                if (ReadInt(exdata, 0) == 1) { var hours = ReadInt(exdata, 4); var minutes = ReadInt(exdata, 8); if (minutes < 10) minutes = '0' + minutes; y += ', at ' + hours + ":" + minutes + ' daily'; }
            }
            x += TableEntry("Periodic connection", addLinkConditional(y, 'editMpsPolicy("Periodic")', xxAccountAdminName));
            x += TableEnd();

            // Show MPS servers
            x += '<br>';
            x += TableStart2();
            x += '<tr><td class=r1 style=padding-left:15px><br>' + "Manage Intel&reg; AMT remote management servers." + '<br><br>';
            if (xxCiraServers.length == 0) {
                x += '<div style=padding-left:15px><br><i>' + "No remote servers found." + '</i></div><br>';
            } else {
                for (var i in xxCiraServers) {
                    var desc = ':' + xxCiraServers[i]['Port'];
                    if (xxCiraServers[i]['CN']) desc += ', ' + xxCiraServers[i]['CN'];
                    x += '<div class=itemBar onclick=showServerDetails(' + i + ')><div style=padding-top:3px><b>' + xxCiraServers[i]['AccessInfo'] + '</b>' + EscapeHtml(desc) + '</div></div>';
                }
            }

            // Show MPS proxies if supported
            if (ciraProxySupport) {
                x += '<br>' + "Manage HTTP proxies used for management connections." + '<br><br>';
                var proxyService = xxRemoteAccess['IPS_HTTPProxyService'].response;
                var proxies = xxRemoteAccess['IPS_HTTPProxyAccessPoint'].responses;
                if (proxies.length == 0) {
                    x += '<div style=padding-left:15px><br><i>' + "No proxies configured." + '</i></div><br>';
                } else {
                    for (var i in proxies) {
                        //x += '<div class=itemBar onclick=showProxyDetails(' + i + ')><div style=padding-top:3px><b>' + EscapeHtml(proxies[i]['AccessInfo']) + ':' + proxies[i]['ProxyPort'] + '</b> / ' + EscapeHtml(proxies[i]['NetworkDnsSuffix']) + '</div></div>';
                        x += '<div class=itemBar onclick=showProxyDetails(' + i + ')><div style=padding-top:3px><b>' + EscapeHtml(proxies[i]['AccessInfo']) + ':' + proxies[i]['Port'] + '</b> / ' + EscapeHtml(proxies[i]['NetworkDnsSuffix']) + '</div></div>';
                    }
                }
            }

            var addserverbutton = '';
            if (xxAccountAdminName) {
                addserverbutton = AddButton("Add Server...", 'AddRemoteAccessServer()');
                if (ciraProxySupport) { addserverbutton += AddButton("Add Proxy...", 'AddRemoteAccessProxy()'); }
            }
            x += '<br><td class=r1>' + TableEnd(AddRefreshButton('PullRemoteAccess()') + addserverbutton);

            QH('id_TableRemoteAccess', x);
        }

        var xxEditMpsPolicyType;
        function editMpsPolicy(type) {
            var x = '', cilaSupport = ((amtversion > 11) || ((amtversion == 11) && (amtversionmin >= 6)));
            xxEditMpsPolicyType = type;
            var name = xxEditMpsPolicyType;
            if (name == 'User') name = "User Initiated";
            var policy = getItem(xxRemoteAccess['AMT_RemoteAccessPolicyRule'].responses, "PolicyRuleName", name);
            x += '<div style=height:26px><select id=d2server1 style=float:right;width:206px onchange=editMpsPolicyUpdate()>';
            x += '<option value=-1>' + "(None)";
            for (var i in xxCiraServers) { x += '<option value=' + i + '' + ((xxPolicies[type][0] && xxPolicies[type][0]['Name'] == xxCiraServers[i]['Name']) ? ' selected' : '') + '>' + xxCiraServers[i]['AccessInfo'] }
            x += '</select><div>' + "Primary server" + '</div></div>';
            if (cilaSupport) { x += '<div style=height:26px><select id=d2server1cira style=float:right;width:206px onchange=editMpsPolicyUpdate()><option value=0>' + "CIRA - External" + '<option value=1' + (((xxPolicies[type][0]) && (xxPolicies[type][0].MpsType == 1))?' selected':'') + '>' + "CILA - Internal" + '</select><div>' + "Primary MPS Type" + '</div></div>'; }
            if (xxCiraServers.length > 1) {
                x += '<div style=height:26px><select id=d2server2 style=float:right;width:206px onchange=editMpsPolicyUpdate()>';
                x += '<option value=-1>' + "(None)";
                for (var i in xxCiraServers) { x += '<option value=' + i + '' + ((xxPolicies[type][1] && xxPolicies[type][1]['Name'] == xxCiraServers[i]['Name']) ? ' selected' : '') + '>' + xxCiraServers[i]['AccessInfo'] }
                x += '</select><div>' + "Secondary server" + '</div></div>';
                if (cilaSupport) { x += '<div style=height:26px><select id=d2server2cira style=float:right;width:206px onchange=editMpsPolicyUpdate()><option value=0>' + "CIRA - External" + '<option value=1' + (((xxPolicies[type][1]) && (xxPolicies[type][1].MpsType == 1)) ? ' selected' : '') + '>' + "CILA - Internal" + '</select><div>' + "Secondary MPS Type" + '</div></div>'; }
            }
            var t, v = 0;
            if (policy) { v = policy['TunnelLifeTime']; }
            x += '<div style=height:26px><input id=d2lifetime style=float:right;width:200px onchange=editMpsPolicyUpdate() value=' + v + '>';
            x += '<div>' + "Tunnel lifetime (Seconds)" + '</div></div>';
            if (type == 'Periodic') {
                t = 0;
                v = 3600;
                if (policy) {
                    var xx = atob(policy['ExtendedData']);
                    t = ReadInt(xx, 0);
                    v = ReadInt(xx, 4);
                    if (t == 1) {
                        var mm = ReadInt(xx, 8);
                        if (mm < 10) mm = '0' + mm;
                        v += ':' + mm;
                    }
                }
                x += '<div style=height:26px><select id=d2ttype style=float:right;width:206px onchange=editMpsPolicyUpdate()>';
                x += '<option value=0' + (t == 0 ? ' selected' : '') + '>' + "Periodic, time interval" + '<option value=1' + (t == 1 ? ' selected' : '') + '>' + "Time of day, once a day";
                x += '</select><div>' + "Trigger type" + '</div></div><div style=height:26px><input id=d2timer style=float:right;width:200px onkeyup=editMpsPolicyUpdate() value=' + v + '><div id=ttypelabel></div></div>';
            }
            setDialogMode(11, format("{0} Connection", type), 3, editMpsPolicyOk, x);
            editMpsPolicyUpdate();
        }

        function editMpsPolicyUpdate() {
            var cilaSupport = ((amtversion > 11) || ((amtversion == 11) && (amtversionmin >= 6)));
            var ok = (xxCiraServers.length <= 1 || ((Q('d2server1').value == -1) || (Q('d2server1').value != Q('d2server2').value)));
            if (ok == true && xxEditMpsPolicyType == 'Periodic' && Q('d2ttype').value == 1) { var hhmm = Q('d2timer').value.split(':'); if (hhmm.length != 2) ok = false; else { var hh = parseInt(hhmm[0]); var mm = parseInt(hhmm[1]); if (hh < 0 || hh > 23 || mm < 0 || mm > 59) ok = false; } }
            QE('idx_dlgOkButton', ok);
            if (xxCiraServers.length > 1) QE('d2server2', Q('d2server1').value != -1);
            if (xxEditMpsPolicyType == 'Periodic') {
                QE('d2timer', Q('d2server1').value != -1);
                QH('ttypelabel', Q('d2ttype').value == 0 ? "Trigger interval (Seconds)" : "Time of day (HH:MM)");
                QE('d2ttype', Q('d2server1').value != -1);
            }
            QE('d2lifetime', Q('d2server1').value != -1);

            // If we are on Intel AMT 11.6 or higher, enable the CIRA/CILA selector when needed.
            if (cilaSupport) {
                QE('d2server1cira', Q('d2server1').value > -1)
                if (xxCiraServers.length > 1) { QE('d2server2cira', (Q('d2server1').value > -1) && (Q('d2server2').value > -1)); }
            }
        }

        function editMpsPolicyOk() {
            var name = xxEditMpsPolicyType;
            if (name == 'User') { name = 'User Initiated'; }

            if (getItem(xxRemoteAccess['AMT_RemoteAccessPolicyRule'].responses, 'PolicyRuleName', name)) {
                // Remove old policy
                amtstack.Delete('AMT_RemoteAccessPolicyRule', { 'PolicyRuleName': name }, editMpsPolicyOk2);
            } else {
                // No old policy to remove, skip this.
                editMpsPolicyOk2();
            }
        }

        function editMpsPolicyOk2(stack, name, responses, status) {
            var cilaSupport = ((amtversion > 11) || ((amtversion == 11) && (amtversionmin >= 6)));
            if (Q('d2server1').value == -1) { PullRemoteAccess(); return; }

            var trigger = 0;
            if (xxEditMpsPolicyType == 'Alert') trigger = 1;
            if (xxEditMpsPolicyType == 'Periodic') trigger = 2;

            // Setup extended data
            var extendedData = null;
            if (trigger == 2) {
                var timertype = Q('d2ttype').value;
                var exdata = IntToStr(Q('d2timer').value); // Interval trigger
                if (timertype == 1) { var hhmm = Q('d2timer').value.split(':'); exdata = IntToStr(parseInt(hhmm[0])) + IntToStr(parseInt(hhmm[1])); } // Time of day trigger
                extendedData = btoa(IntToStr(timertype) + exdata);
            }

            // Create the MPS server references
            var server1, server2;
            if (Q('d2server1').value >= 0) { server1 = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_ManagementPresenceRemoteSAP</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="Name">' + xxCiraServers[Q('d2server1').value]['Name'] + '</Selector></SelectorSet></ReferenceParameters>'; }
            if (Q('d2server1').value >= 0 && xxCiraServers.length > 1 && Q('d2server2').value >= 0) { server2 = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_ManagementPresenceRemoteSAP</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="Name">' + xxCiraServers[Q('d2server2').value]['Name'] + '</Selector></SelectorSet></ReferenceParameters>'; }

            // Put the CIRA/CILA servers in the right bins.
            var ciraServers = [];
            var cilaServers = [];
            if (cilaSupport) {
                // Only Intel AMT 11.6 supports this
                if (server1) {
                    if (Q('d2server1cira').value == 0) { ciraServers.push(server1); } else { cilaServers.push(server1); }
                    if (server2) { if (Q('d2server2cira').value == 0) { ciraServers.push(server2); } else { cilaServers.push(server2); } }
                }
            } else {
                // If older than Intel AMT 11.6, put all servers in the CIRA bucket.
                if (server1) { ciraServers.push(server1); if (server2) { ciraServers.push(server2); } }
            }

            // Go ahead and create the new CIRA/CILA policy.
            amtstack.AMT_RemoteAccessService_AddRemoteAccessPolicyRule(trigger, Q('d2lifetime').value, extendedData, ciraServers, cilaServers, PullRemoteAccess);
        }

        var editEnvironmentDetectionTmp;
        function editEnvironmentDetection(a) {
            if (a != 1) { editEnvironmentDetectionTmp = (xxEnvironementDetection['DetectionStrings']) ? Clone(xxEnvironementDetection['DetectionStrings']) : []; }
            var x = '';
            if (xxAccountAdminName) x += "Enter up to 5 intranet domain suffix. If the computer is outside these domains, Intel&reg; AMT local ports will be closed and remote server connections will be active." + '<br><br>';
            if (editEnvironmentDetectionTmp.length == 0) { x += '<i>' + "No intranet domains, Environement detection disabled." + '</i><br>'; }
            for (var i in editEnvironmentDetectionTmp) { x += '<div class=itemBar style=margin-right:0><div style=float:right>' + AddButton2("Remove", 'editEnvironmentDetectionRemove(' + i + ')') + '</div><div style=padding-top:3px;max-width:260px;overflow:hidden title="' + editEnvironmentDetectionTmp[i] + '"><b>' + editEnvironmentDetectionTmp[i] + '</b></div></div>'; }
            if (xxAccountAdminName && editEnvironmentDetectionTmp.length < 5) { x += '<br><input id=edInput placeholder=intranet.org style=width:276px onkeyup=edInputChg() maxlength=63><input type=button id=edAdd value=Add style=width:80px;margin-left:5px onclick=editEnvironmentDetectionAdd()>'; }
            if (a == 1) QH('id_dialogOptions', x); else setDialogMode(11, "Environment Detection", xxAccountAdminName?3:1, editEnvironmentDetectionDlg, x);
            edInputChg();
        }

        function editEnvironmentDetectionDlg() {
            if (xxAccountAdminName) {
                var t = Clone(xxEnvironementDetection);
                t['DetectionStrings'] = editEnvironmentDetectionTmp;
                //console.log('AMT_EnvironmentDetectionSettingData', t);
                amtstack.Put('AMT_EnvironmentDetectionSettingData', t, editEnvironmentDetectionDlg2, 0, 1);
            }
        }

        function editEnvironmentDetectionDlg2(stack, name, response, status) {
            if (status != 200) { messagebox("Environment Detection", format("Failed to add server, status {0}", status)); }
            else if ((response.Body['ReturnValue']) && (response.Body['ReturnValue'] != 0)) { messagebox("Environment Detection", response.Body.ReturnValueStr.replace(/_/g, ' ')); }
            else { PullRemoteAccess(); }
        }

        function edInputChg() {
            if (editEnvironmentDetectionTmp.length < 5) QE('edAdd', Q('edInput').value.length > 0);
        }

        function editEnvironmentDetectionAdd() {
            editEnvironmentDetectionTmp.push(Q('edInput').value);
            editEnvironmentDetection(1);
        }

        function editEnvironmentDetectionRemove(h) {
            editEnvironmentDetectionTmp.splice(h, 1);
            editEnvironmentDetection(1);
        }

        function editUserInitiatedCira() {
            if (xxdialogMode) return;
            var s = '';
            for (var i in xxUserInitiatedEnabledState) { s += '<input type=radio name=d11 id=wl' + i + ' value=' + i + ' ' + ((xxUserInitiatedCira['EnabledState'] == i) ? 'checked' : '') + '>' + xxUserInitiatedEnabledState[i] + '<br>'; }
            setDialogMode(11, "User Initiated Tunnel", 3, editUserInitiatedCiraDlg, s);
        }

        function editUserInitiatedCiraDlg() { amtstack.AMT_UserInitiatedConnectionService_RequestStateChange(document.querySelector('input[name=d11]:checked').value, null, editUserInitiatedCiraDlg2); }
        function editUserInitiatedCiraDlg2(stack, name, response, status) { if (status == 200) { amtstack.Get('AMT_UserInitiatedConnectionService', editUserInitiatedCiraDlg3, 0, 1); } }
        function editUserInitiatedCiraDlg3(stack, name, response, status) { if (status == 200) { xxUserInitiatedCira = response.Body; updateRemoteAccess(); } }

        var xxShowServerDetailsHandle;
        function showServerDetails(h) {
            xxShowServerDetailsHandle = h;
            var server = xxCiraServers[h];
            var x = '';
            x += addHtmlValue("Access Name", server['AccessInfo']);
            if (server['Port']) x += addHtmlValue("Port", server['Port']);
            if (server['CN']) x += addHtmlValue("Common Name", server['CN']);

            var credentiallink = getElementWithContextSelectorValue(xxRemoteAccessCredentiaLinks, server['Name']);
            if (credentiallink) {
                var credentialselectorvalue = credentiallink['ElementInContext']['ReferenceParameters']['SelectorSet']['Selector']['Value'];
                if (credentialselectorvalue.indexOf('Username') > 0) {
                    x += addHtmlValue("Authentication Type", "User & Pass / Server-Auth TLS");
                    x += addHtmlValue("Remote ID", getInstance(xxMPSUserPass, credentialselectorvalue)['RemoteID']);
                } else {
                    x += addHtmlValue("Authentication Type", "Certificate / Mutual-Auth TLS");
                    // ###BEGIN###{!Certificates}
                    var c = getInstance(xxRemoteAccess['AMT_PublicKeyCertificate'].responses, credentialselectorvalue);
                    // ###END###{!Certificates}
                    // ###BEGIN###{Certificates}
                    var c = getInstance(xxCertificates, credentialselectorvalue);
                    // ###END###{Certificates}
                    x += addHtmlValue("Certificate Name", parseCertName(c['Subject'])['CN']);
                }
            }

            var buttons = 1;
            if (xxAccountAdminName) buttons = 5;
            setDialogMode(11, "Remote Server #" + (h + 1), buttons, showServerDetailsOk, x);
        }

        function getElementWithContextSelectorValue(elements, value) {
            for (var i in elements) {
                elements[i]['ElementProvidingContext']['ReferenceParameters']['SelectorSet']['Selector'] = MakeToArray(elements[i]['ElementProvidingContext']['ReferenceParameters']['SelectorSet']['Selector']);
                for (var j in elements[i]['ElementProvidingContext']['ReferenceParameters']['SelectorSet']['Selector']) { if (elements[i]['ElementProvidingContext']['ReferenceParameters']['SelectorSet']['Selector'][j]['Value'] == value) return elements[i]; }
            }
            return null;
        }

        function showServerDetailsOk(r) {
            // Delete the selected CIRA server 
            if (r == 2) { amtstack.Delete('AMT_ManagementPresenceRemoteSAP', { 'Name': xxCiraServers[xxShowServerDetailsHandle]['Name'] }, showServerDetailsOk2); }
        }

        function showServerDetailsOk2(stack, name, responses, status) {
            if (status == 408) { messagebox("Remote Server Removal", "Unable to remove server, access denied."); } else { PullRemoteAccess(); }
        }

        function parseCertName(x) {
            var j, r = {}, xx = x.split(',');
            for (var i in xx) { j = xx[i].indexOf('='); r[xx[i].substring(0, j)] = xx[i].substring(j + 1); }
            return r;
        }
        
        function showProxyDetails(h) {
            var proxy = xxRemoteAccess['IPS_HTTPProxyAccessPoint'].responses[h];

            var x = addHtmlValue("Access name", proxy['AccessInfo'] + ':' + proxy['ProxyPort']);
            x += addHtmlValue("DNS suffex", proxy['NetworkDnsSuffix']);
            //x += addHtmlValue("Proxy type", ['Administrator', 'Operating system'][proxy['ProxyType']]);
            x += addHtmlValue("Proxy type", ['Administrator', 'Operating system'][proxy['Type']]);
            //x += addHtmlValue("Last time used", proxy['LastTimeUsed']);

            var buttons = 1;
            if (xxAccountAdminName) { buttons = 5; }
            setDialogMode(11, "HTTP Proxy #" + (h + 1), buttons, showProxyDetailsOk, x, h);
        }

        function showProxyDetailsOk(r, h) {
            // Delete the selected proxy server
            var proxy = xxRemoteAccess['IPS_HTTPProxyAccessPoint'].responses[h];
            if (r == 2) { amtstack.Delete('IPS_HTTPProxyAccessPoint', { 'Name': proxy['Name'] }, showProxyDetailsOk2); }
        }

        function showProxyDetailsOk2(stack, name, responses, status) {
            if (status == 408) { messagebox("HTTP Proxy Removal", "Unable to remove HTTP proxy, access denied."); } else { PullRemoteAccess(); }
        }

        function AddRemoteAccessProxy() {
            // AddRemoteAccessProxy Host name = 2, Ipv4 = 3, Ipv6 = 4
            var x = '<div style=height:26px><select id=d2type style=float:right;width:206px onchange=AddRemoteAccessProxyUpdate()><option value=2>' + "Hostname FQDN" + '<option value=3>' + "IPv4 address" + '<option value=4>' + "IPv6 address" + '</select><div>' + "Connection type" + '</div></div>';
            x += '<div style=height:26px><input id=d2host style=float:right;width:200px maxlength=255 onkeyup=AddRemoteAccessProxyUpdate()><div id=d2typespan></div></div>';
            x += '<div style=height:26px><input id=d2port onkeypress="return (event.charCode == 0 || (event.charCode >= 48 && event.charCode <= 57))" style=float:right;width:200px onkeyup=AddRemoteAccessProxyUpdate()><div>' + "Port" + '</div></div>';
            x += '<div style=height:26px><input id=d2domain style=float:right;width:200px maxlength=191 onkeyup=AddRemoteAccessProxyUpdate()><div>' + "DNS suffix" + '</div></div>';
            setDialogMode(11, "Add HTTP Proxy", 3, AddRemoteAccessProxyOk, x);
            AddRemoteAccessProxyUpdate();
        }

        function AddRemoteAccessProxyUpdate() {
            var ok = (Q('d2host').value.length != 0) && (Q('d2domain').value.length != 0);
            if ((Q('d2port').value.length == 0) || (parseInt(Q('d2port').value) > 65535)) { ok = false; }
            QE('idx_dlgOkButton', ok);
            QH('d2typespan', ['', '', "FQDN / hostname", "IPv4 address", "IPv6 address"][Q('d2type').value]);
        }

        function AddRemoteAccessProxyOk() {
            amtstack.IPS_HTTPProxyService_AddProxyAccessPoint(Q('d2host').value, Q('d2type').value, parseInt(Q('d2port').value), Q('d2domain').value, AddRemoteAccessProxyOk2);
        }

        function AddRemoteAccessProxyOk2(stack, name, response, status) {
            if (status != 200) {
                messagebox("Add Proxy Server", "Failed to add proxy, status " + status);
            } else if (response.Body['ReturnValue'] != 0) {
                messagebox("Add Proxy Server", response.Body.ReturnValueStr.replace(/_/g, ' '));
            } else {
                PullRemoteAccess();
            }
        }

        function AddRemoteAccessServer() {
            // ###BEGIN###{!Certificates}
            var certs = xxRemoteAccess['AMT_PublicKeyCertificate'].responses;
            // ###END###{!Certificates}
            // ###BEGIN###{Certificates}
            var certs = [];
            for (var i in xxCertificates) { if (xxCertificates[i].XPrivateKey) { certs.push(xxCertificates[i]); } }
            // ###END###{Certificates}
            var x = '';
            x += '<div style=height:26px><select id=d2type style=float:right;width:206px onchange=AddRemoteAccessServerUpdate()><option value=201>' + "Hostname FQDN" + '<option value=3>' + "IPv4 address" + '</select><div>' + "Connection type" + '</div></div>';
            x += '<div style=height:26px><input id=d2name style=float:right;width:200px onkeyup=AddRemoteAccessServerUpdate()><div id=d2lname></div></div>';
            x += '<div style=height:26px><input id=d2port onkeypress="return (event.charCode == 0 || (event.charCode >= 48 && event.charCode <= 57))" style=float:right;width:200px value=4433 onkeyup=AddRemoteAccessServerUpdate()><div>' + "Server port" + '</div></div>';
            x += '<div style=height:26px id=d2ucn><input id=d2cn style=float:right;width:200px onkeyup=AddRemoteAccessServerUpdate()><div>' + "Server Common Name" + '</div></div>';
            x += '<div style=height:26px><select id=d2auth style=float:right;width:206px onchange=AddRemoteAccessServerUpdate()>';
            if (certs.length > 0) { x += '<option value=1>' + "Certificate"; }
            x += '<option value=2>' + "Username/Password" + '</select><div>' + "Authentication type" + '</div></div>';
            x += '<span id=d2utype>';
            x += '<div style=height:26px><input id=d2user style=float:right;width:200px onkeyup=AddRemoteAccessServerUpdate()><div>' + "Username" + '</div></div>';
            x += '<div style=height:26px><input id=d2pass style=float:right;width:200px onkeyup=AddRemoteAccessServerUpdate()><div>' + "Strong Password" + '</div></div>';
            x += '</span>';
            x += '<span id=d2ctype>';
            x += '<div style=height:26px><select id=d2cert style=float:right;width:206px onchange=AddRemoteAccessServerUpdate()>';
            for (var i in certs) { x += '<option value=' + certs[i]['InstanceID'].substring(34) + '>' + parseCertName(certs[i]['Subject'])['CN']; }
            x += '</select><div>' + "Certificate" + '</div></div></span>';
            setDialogMode(11, "Add Remote Server", 3, AddRemoteAccessServerOk, x);
            AddRemoteAccessServerUpdate();
        }

        function AddRemoteAccessServerOk() {
            var cref, user, pass, cn;
            if (Q('d2auth').value == 1) {
                cref = '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyCertificate</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT Certificate: Handle: ' + Q('d2cert').value + '</Selector></SelectorSet></ReferenceParameters>';
            } else {
                user = Q('d2user').value;
                pass = Q('d2pass').value;
            }
            if (Q('d2cn').value.length > 0) cn = Q('d2cn').value;
            amtstack.AMT_RemoteAccessService_AddMpServer(Q('d2name').value, Q('d2type').value, Q('d2port').value, Q('d2auth').value, cref, user, pass, cn, AddRemoteAccessServerOk2);
        }

        function AddRemoteAccessServerOk2(stack, name, response, status) {
            if (status != 200) {
                messagebox("Add Internet Server", format("Failed to add server, status {0}", status));
            } else if (response.Body['ReturnValue'] != 0) {
                messagebox("Add Internet Server", response.Body.ReturnValueStr.replace(/_/g, ' '));
            } else {
                PullRemoteAccess();
            }
        }

        function AddRemoteAccessServerUpdate() {
            var ok = (Q('d2name').value.length != 0);
            if (Q('d2type').value == 3 && ok == true)  { ok = (Q('d2cn').value.length != 0); }
            if (Q('d2auth').value == 2 && ok == true) { ok = ((Q('d2user').value.length != 0) && (passwordcheck(Q('d2pass').value))); }
            if ((Q('d2port').value.length == 0) || (parseInt(Q('d2port').value) > 65535)) { ok = false; }
            if ((Q('d2name').value.indexOf(':') != -1) || ((Q('d2type').value == 3) && (Q('d2cn').value.indexOf(':') != -1))) { ok = false; }
            QH('d2lname', (Q('d2type').value == 201) ? "Hostname" : "IPv4 Address");
            QV('d2utype', Q('d2auth').value == 2);
            QV('d2ucn', Q('d2type').value == 3);
            QV('d2ctype', Q('d2auth').value == 1);
            QE('idx_dlgOkButton', ok);
        }

        // ###END###{RemoteAccess}

        //
        // Edit Computer Name & DNS feature
        //

        function showEditNameDlg(x) {
            if (xxdialogMode) return;
            var t = amtsysstate['AMT_GeneralSettings'].response['HostName'], y = amtsysstate['AMT_GeneralSettings'].response['DomainName'];
            if (y != null && y.length > 0) t += '.' + y;
            var r = '<br><div style=height:26px><input id=d11name value="' + t + '" style=float:right;width:200px><div>' + "Name & Domain" + '</div></div>';
            if (x == 1) {
                var s = (amtsysstate['AMT_GeneralSettings'].response['SharedFQDN'] == true);
                r += '<div style=height:26px><select id=d11fqdn style=float:right;width:200px><option value=true ' + (s?'selected':'') + '>' + "Shared, same as OS" + '<option value="false" ' + (s?'':'selected') + '>' + "Dedicated, different from OS" + '</select><div>' + "Name Sharing" + '</div></div>';
            }
            setDialogMode(11, "Computer Name", 3, editNameDlgOk, r);
        }

        function editNameDlgOk() {
            var i = Q('d11name').value, j = i.indexOf('.'), k = '';
            if (j >= 0) { k = i.substring(j + 1); i = i.substring(0, j); }
            var clone = Clone(amtsysstate['AMT_GeneralSettings'].response);
            clone['HostName'] = i;
            clone['DomainName'] = k;
            if (Q('d11fqdn')) { clone['SharedFQDN'] = d11fqdn.value; }
            amtstack.Put('AMT_GeneralSettings', clone, function() { amtstack.Get('AMT_GeneralSettings', computerNameGet, 0, 1); }, 0, 1);
        }

        function computerNameGet(stack, name, response, status) {
            if (status == 200) { amtsysstate['AMT_GeneralSettings'].response = response.Body; updateSystemStatus(); }
        }

        function showEditDnsDlg() {
            if (xxdialogMode) return;
            var g = amtsysstate['AMT_GeneralSettings'].response;
            var v = 0;
            if (g['DDNSUpdateByDHCPServerEnabled'] == true) v = 1;
            if (g['DDNSUpdateEnabled'] == true) v = 2;
            idx_d23ddns.value = v;
            idx_d23interval.value = g['DDNSPeriodicUpdateInterval'];
            idx_d23ttl.value = g['DDNSTTL'];
            showEditDnsDlgChange();
            setDialogMode(23, "Dynamic DNS client", 3, showEditDnsDlgOk);
        }

        function showEditDnsDlgOk() {
            var clone = Clone(amtsysstate['AMT_GeneralSettings'].response);
            clone['DDNSUpdateEnabled'] = ((idx_d23ddns.value == 2)?true:false);
            clone['DDNSUpdateByDHCPServerEnabled'] = ((idx_d23ddns.value == 1)?true:false);
            if (idx_d23ddns.value == 2) {
                clone['DDNSPeriodicUpdateInterval'] = idx_d23interval.value;
                clone['DDNSTTL'] = idx_d23ttl.value;
            }
            amtstack.Put('AMT_GeneralSettings', clone, function() { amtstack.Get('AMT_GeneralSettings', computerNameGet, 0, 1); }, 0, 1);
        }

        function showEditDnsDlgChange() {
            QE('idx_d23interval', idx_d23ddns.value == 2);
            QE('idx_d23ttl', idx_d23ddns.value == 2);
        }

        //
        // Intel AMT Features
        //

        function showFeaturesDlg() {
            if (xxdialogMode || !xxAccountAdminName) return;
            idx_d9redir.checked = amtfeatures[0], idx_d9kvm.checked = amtfeatures[3], idx_d9ider.checked = amtfeatures[2], idx_d9sol.checked = amtfeatures[1];
            QV('idx_d9kvm_div', amtfeatures[3] != null);
            setDialogMode(9, "Intel&reg; AMT Features", 3, featuresDlgOk)
        }

        function featuresDlgOk() {
            var r = amtsysstate['AMT_RedirectionService'].response;
            r['ListenerEnabled'] = idx_d9redir.checked;
            r['EnabledState'] = 32768 + ((idx_d9ider.checked?1:0) + (idx_d9sol.checked?2:0));
            amtstack.AMT_RedirectionService_RequestStateChange(r['EnabledState'],
                function (stack, name, response, status) {
                    if (status != 200) { messagebox("Error", "RedirectionService, RequestStateChange Error " + status); return; }
                    if (amtfeatures[3] != null) {
                        amtstack.CIM_KVMRedirectionSAP_RequestStateChange((idx_d9kvm.checked) ? 2 : 3, 0,
                        function (stack, name, response, status) {
                            if (status != 200) { messagebox("Error", "KVMRedirectionSAP, RequestStateChange Error " + status); return; }
                            amtstack.Put('AMT_RedirectionService', r, function (stack, name, response, status) {
                                if (status != 200) { messagebox("Error", "RedirectionService PUT Error " + status); return; }
                                amtstack.Get('AMT_RedirectionService', featuresDlgGet1, 0, 1);
                                amtstack.Get('CIM_KVMRedirectionSAP', featuresDlgGet2, 0, 1)
                            }, 0, 1) }
                        );
                    }
                }
            );
        }

        function featuresDlgGet1(stack, name, response, status) {
            if (status == 200) { amtsysstate['AMT_RedirectionService'].response = response.Body; updateSystemStatus(); }
        }

        function featuresDlgGet2(stack, name, response, status) {
            if (status == 200) { amtsysstate['CIM_KVMRedirectionSAP'].response = response.Body; updateSystemStatus(); }
        }

        //
        // Intel AMT Boot Features
        //

        function showEnableBootServiceDlg() {
            if (xxdialogMode) return;
            if (amtsysstate['CIM_BootService'].response['EnabledState'] != null) {
                QV('d26rpediv', amtversion > 15);
                if (amtversion > 15) {
                    idx_d26rpe1.checked = (amtsysstate['CIM_BootService'].response['EnabledState'] & 2)
                    idx_d26rpe0.checked = !idx_d26rpe1.checked;
                }
                idx_d26ocr1.checked = (amtsysstate['CIM_BootService'].response['EnabledState'] & 1)
                idx_d26ocr0.checked = !idx_d26ocr1.checked;
            }
            setDialogMode(26, "Boot Features", 3, showEnableBootServiceDlgOk)
        }

        function showEnableBootServiceDlgOk() {
            var v = 32768 + parseInt(document.querySelector('input[name=d26a]:checked').value);
            if (amtversion > 15) { v += parseInt(document.querySelector('input[name=d26b]:checked').value); }
            amtstack.CIM_BootService_RequestStateChange(v, null, showEnableBootServiceDlgResponse, v);
        }

        function showEnableBootServiceDlgResponse(stack, name, response, status, tag) {
            if (status == 200) {
                if (response.Body['ReturnValueStr'] != 'SUCCESS') { messagebox("Boot Features Error", response.Body['ReturnValueStr']); }
                amtstack.Get('CIM_BootService', showEnableBootServiceDlgResponse2, tag);
                PullSystemStatus();
            } else {
                if (response.Header['WsmanError']) {
                    messagebox("Boot Features Error", response.Header['WsmanError'].replace(/_/g, ' '));
                } else {
                    messagebox("Boot Features Error", "Error, Status = " + status);
                }
            }
        }

        function showEnableBootServiceDlgResponse2(stack, name, response, status, tag) {
            if ((status == 200) && (response.Body['EnabledState'] != tag)) { messagebox("Boot Features Error", "Unable to set OCR/RPE, check that these features are enabled in BIOS."); }
        }

        //
        // Intel AMT User Consent
        //

        function showConsentDlg() {
            if (xxdialogMode) return;
            var optinrequired = amtsysstate['IPS_OptInService'].response['OptInRequired'];
            idx_d10none.checked = (optinrequired == 0);
            idx_d10kvm.checked = (optinrequired == 1);
            idx_d10all.checked = (optinrequired == 0xFFFFFFFF);
            setDialogMode(10, "User Consent", 3, consentDlgOk)
        }

        function consentDlgOk() {
            amtsysstate['IPS_OptInService'].response['OptInRequired'] = document.querySelector('input[name=d10]:checked').value;
            amtstack.Put('IPS_OptInService', amtsysstate['IPS_OptInService'].response, function() { amtstack.Get('IPS_OptInService', consentGet, 0, 1); }, 0, 1);
        }

        function consentGet(stack, name, response, status) {
            if (status == 200) { PullSystemStatus(); }
        }

        //
        // NETWORK SETTINGS
        //

// ###BEGIN###{NetworkSettings}

        /*
        IPv6 %AddrType%:
            0 - Address generated from: fe80::/64 + Interface ID,
            1 - Address generated from: [Router advertised prefix] + [Interface ID],
            2 - Global IPv6 address obtained from DHCPv6 Server,
            3 - IPv6 unicast address configured by the user,
            4 - Returned by FW for IPv6 addresses that are not owned by FW (such as IPv6 router address, configuration server address etc.)

        IPv6 %AddrState%:
            0 - DAD is still in process for this address,
            1 - Address is valid and may be used for new communication,
            2 - Address is deprecated and should not be used for new communication,
            3 - Covers both the preferred and deprecated states,
            4 - The valid lifetime of the address has expired,
            5 - An interface ID collision has been detected for this address when performing DAD,
            6 - Returned by FW for IPv6 addresses that are not owned by FW (such as IPv6 router address, configuration server address etc.
        */
        // ipv6addrtype are element 0 to 4, ipv6addrstate are 5 and after. Merged both arrays to cut down size
        var ipv6addrtype = ["Link local address", "Network local address", "Global address", "User configured", "Not allowed", "DAD in progress", "valid", "deprecated", "preferred/deprecated", "expired", "collision", "not allowed"];
        function showIPv6AddrDlg(netifid, addrstr) {
            if (xxdialogMode) return;
            var x = TableStart();
            t = addrstr.split(',');
            for (var i = 0; i < t.length; i += 3) {
                x += TableEntry('<b>' + t[i] + '</b><br><span style=font-size:10px>' + ipv6addrtype[t[i + 1]] + ", " + ipv6addrtype[+t[i + 2] + 5] + '</span>', '');
            }
            setDialogMode(11, (netifid == 0 ? "IPv6 addresses for wired interface" : "IPv6 addresses for wireless interface"), 1, null, x + TableEnd());
        }

        function showIPv6StateDlg(netifid, state) {
            if (xxdialogMode || !amtsysstate) return;
            var zz = amtsysstate['IPS_IPv6PortSettings'].responses[netifid];
            ipv6manual = (netifid == 0 && (isIpAddress(zz['IPv6Address']) || isIpAddress(zz['DefaultRouter']) || isIpAddress(zz['PrimaryDNS']) || isIpAddress(zz['SecondaryDNS'])));

            QV('id_d21manualdiv', netifid == 0);
            QV('id_d21subnetdiv', false);
            QV('d21o0', true);
            QV('d21l0', true);
            QH('d21l0', "IPv6 disabled");
            QH('d21l1', "IPv6 enabled, automatic");
            QH('d21l2', "IPv6 enabled, automatic + manual addresse");
            d21o0.checked = !state;
            d21o1.checked = state && !ipv6manual;
            d21o2.checked = state && ipv6manual;
            idx_d21address.value = isIpAddress(zz['IPv6Address'],'');
            idx_d21gateway.value = isIpAddress(zz['DefaultRouter'],'');
            idx_d21dns1.value = isIpAddress(zz['PrimaryDNS'],'');
            idx_d21dns2.value = isIpAddress(zz['SecondaryDNS'],'');
            setDialogMode(21, (netifid == 0 ? "IPv6 support for wired interface" : "IPv6 support for wireless interface"), 3, function () { showIPv6StateDlgOk(netifid) })
            updateIPSetupDlg();
        }

        function showIPv6StateDlgOk(netifid) {
            var selector = '<w:SelectorSet><w:Selector Name="InstanceID">Intel(r) IPS IPv6 Settings ' + netifid + '</w:Selector></w:SelectorSet>';
            var zz = amtsysstate['IPS_IPv6PortSettings'].responses[netifid];
            if (netifid == 0) { // We can only set IPv6 manual address for wired interface
                if (d21o1.checked) { // Fully automatic, clear all addresses
                    zz['IPv6Address'] = zz['DefaultRouter'] = zz['PrimaryDNS'] = zz['SecondaryDNS'] = '::';
                    amtstack.Put('IPS_IPv6PortSettings', zz, showIPv6StateDlgDone, null, 0, selector);
                }
                if (d21o2.checked) { // Manual, set addresses
                    zz['IPv6Address'] = (idx_d21address.value == '') ? '::' : idx_d21address.value.toLocaleLowerCase();
                    zz['DefaultRouter'] = (idx_d21gateway.value == '') ? '::' : idx_d21gateway.value.toLocaleLowerCase();
                    zz['PrimaryDNS'] = (idx_d21dns1.value == '') ? '::' : idx_d21dns1.value.toLocaleLowerCase();
                    zz['SecondaryDNS'] = (idx_d21dns2.value == '') ? '::' : idx_d21dns2.value.toLocaleLowerCase();
                    amtstack.Put('IPS_IPv6PortSettings', zz, showIPv6StateDlgDone, null, 0, selector);
                }
            }
            // This code enables/disables IPv6 for a given interface.
            var elementSettings = amtsysstate['CIM_ElementSettingData'].responses;
            for (var i = 0; i < elementSettings.length; i++) {
                if (elementSettings[i]['SettingData'] && elementSettings[i]['SettingData']['ReferenceParameters']['SelectorSet']['Selector']['Value'] == ('Intel(r) IPS IPv6 Settings ' + netifid)) {
                    var CreationClassName = getItem(elementSettings[i]['ManagedElement']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'CreationClassName').Value;
                    var DeviceID = getItem(elementSettings[i]['ManagedElement']['ReferenceParameters']['SelectorSet']['Selector'], '@Name', 'DeviceID').Value;
                    var selector2 = '<w:SelectorSet><w:Selector Name="ManagedElement"><a:EndpointReference xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/' + CreationClassName + '</w:ResourceURI><w:SelectorSet><w:Selector Name="CreationClassName">' + CreationClassName + '</w:Selector><w:Selector Name="DeviceID">' + DeviceID + '</w:Selector><w:Selector Name="SystemCreationClassName">CIM_ComputerSystem</w:Selector><w:Selector Name="SystemName">Intel(r) AMT</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference></w:Selector><w:Selector Name="SettingData"><a:EndpointReference xmlns:b="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:c="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address><a:ReferenceParameters><w:ResourceURI>http://intel.com/wbem/wscim/1/ips-schema/1/IPS_IPv6PortSettings</w:ResourceURI><w:SelectorSet><w:Selector Name="InstanceID">Intel(r) IPS IPv6 Settings ' + netifid + '</w:Selector></w:SelectorSet></a:ReferenceParameters></a:EndpointReference></w:Selector></w:SelectorSet>';
                    var clone = Clone(elementSettings[i]);
                    clone['IsCurrent'] = ((d21o0.checked) ? 2 : 1);
                    amtstack.Put('CIM_ElementSettingData', clone, showIPv6StateDlgDone, null, 0, selector2);
                }
            }
        }

        function showIPv6StateDlgDone(stack, name, response, status) {
            if (status == 200) {
                amtsysstate = undefined;
                PullSystemStatus();
            } else {
                messagebox("IPv6 support", format("Unable to set IPv6 state, error {0}", status));
            }
        }

        function showPingActionDlg() {
            if (xxdialogMode) return;
            var g = amtsysstate['AMT_GeneralSettings'].response;
            var v = (g['PingResponseEnabled'] == true) + ((g['RmcpPingResponseEnabled'] == true) << 1);
            d20a.checked = (v == 0);
            d20b.checked = (v == 1);
            d20c.checked = (v == 2);
            d20d.checked = (v == 3);
            setDialogMode(20, "Intel&reg; AMT Ping Response", 3, showPingActionDlgOk);
        }

        function showPingActionDlgOk() {
            var clone = Clone(amtsysstate['AMT_GeneralSettings'].response);
            var v = document.querySelector('input[name=d20]:checked').value;
            clone['PingResponseEnabled'] = ((v & 1) != 0);
            clone['RmcpPingResponseEnabled'] = ((v & 2) != 0);
            amtstack.Put('AMT_GeneralSettings', clone, PullSystemStatus, 0, 1);
        }

        function showIPSetupDlg() {
            if ((xxdialogMode) || (amtsysstate == null)) return;
            var x = amtsysstate['AMT_EthernetPortSettings'].responses[0];
            QV('id_d21ipaddrsync', amtversion > 6);
            if (amtversion > 6) { Q('d21ipsync').checked = x['IpSyncEnabled']; };
            QV('id_d21manualdiv', true);
            QV('id_d21subnetdiv', true);
            QV('d21o0', false);
            QV('d21l0', false);
            QH('d21l1', "Automatic configuration using DHCP server");
            QH('d21l2', "Static configuration using IPv4 settings below");
            d21o1.checked = (x['DHCPEnabled'] == true);
            d21o2.checked = !d21o1.checked;
            idx_d21address.value = isIpAddress(x['IPAddress'],'');
            idx_d21subnet.value = isIpAddress(x['SubnetMask'],'');
            idx_d21gateway.value = isIpAddress(x['DefaultGateway'],'');
            idx_d21dns1.value = isIpAddress(x['PrimaryDNS'],'');
            idx_d21dns2.value = isIpAddress(x['SecondaryDNS'],'');
            updateIPSetupDlg();
            setDialogMode(21, "IPv4 Settings", 3, showIPSetupDlgOk)
        }

        function updateIPSetupDlg() {
            var ok = true;
            if (d21o2.checked && (Q('d21l2').innerHTML == "IPv6 enabled, automatic + manual addresse") && (idx_d21address.value.split(':').length < 2)) { ok = false; }
            QE('idx_dlgOkButton', ok);
            idx_d21address.disabled = idx_d21subnet.disabled = idx_d21gateway.disabled = idx_d21dns1.disabled = idx_d21dns2.disabled = !(d21o2.checked && ((amtversion < 7) || (Q('d21ipsync').checked == false)));
        }

        function showIPSetupDlgOk() {
            var x = Clone(amtsysstate['AMT_EthernetPortSettings'].responses[0]);
            x['DHCPEnabled'] = d21o1.checked;
            delete x['IPAddress'];
            delete x['SubnetMask'];
            delete x['DefaultGateway'];
            delete x['PrimaryDNS'];
            delete x['SecondaryDNS'];
            if (amtversion > 6) { x['IpSyncEnabled'] = Q('d21ipsync').checked; }
            if ((d21o1.checked == false) && (Q('d21ipsync').checked == false)) { // || (amtversion < 7)
                x['IPAddress'] = idx_d21address.value;
                x['SubnetMask'] = idx_d21subnet.value;
                x['DefaultGateway'] = idx_d21gateway.value;
                if (idx_d21dns1.value != '') x['PrimaryDNS'] = idx_d21dns1.value;
                if (idx_d21dns2.value != '') x['SecondaryDNS'] = idx_d21dns2.value;
            }
            amtstack.Put('AMT_EthernetPortSettings', x, showIPSetupDlgDone, 0, 1, x);
        }

        function showIPSetupDlgDone(stack, name, response, status) {
            if (status == 200) {
                amtsysstate = undefined;
                PullSystemStatus();
            } else {
                messagebox("IPv4 Settings", format("Unable to set network parameters, error {0}", status));
            }
        }

// ###END###{NetworkSettings}

// ###BEGIN###{PowerControl}

        //
        // POWER ACTIONS
        //

        amtPowerBootCapabilities = null;
        function showPowerActionDlg() {
            if (xxdialogMode) return;
            statusbox("Power Actions", "Checking capabilities...");
            amtstack.Get('AMT_BootCapabilities', powerActionResponse00, 0, 1);
        }

        function showPowerActionDlg() {
            if (xxdialogMode) return;
            var powerState = 3;
            try {
                var x = amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'];
                if (x == 2) { powerState = 1; } else { powerState = 2; }
            } catch (ex) { }
            amtPowerBootCapabilities = amtsysstate['AMT_BootCapabilities'].response;
            QH('d5actionSelect', '');
            if (powerState & 2) { addOption('d5actionSelect', "Power up", 2); }
            if (powerState & 1) {
                addOption('d5actionSelect', "Reset", 10);
                addOption('d5actionSelect', "Power cycle", 5);
                addOption('d5actionSelect', "Power down", 8);
            }
            if (amtPowerBootCapabilities['ForceDiagnosticBoot'] == true) {
                if (powerState & 2) { addOption('d5actionSelect', "Power on to diagnostic", 300); }
                if (powerState & 1) { addOption('d5actionSelect', "Reset to diagnostic", 301); }
            }
            if ((amtversion > 9) && (powerState & 1)) {
                addOption('d5actionSelect', "OS Wake from Standby", 500);
                addOption('d5actionSelect', "OS Power Saving", 501);
                addOption('d5actionSelect', "Soft-off", 12);
                addOption('d5actionSelect', "Soft-reset", 14);
                addOption('d5actionSelect', "Sleep", 4);
                addOption('d5actionSelect', "Hibernate", 7);
            }
            if (amtPowerBootCapabilities['BIOSSetup'] == true) {
                if (powerState & 2) { addOption('d5actionSelect', "Power up to BIOS", 100); }
                if (powerState & 1) { addOption('d5actionSelect', "Reset to BIOS", 101); }
            }
            if (amtPowerBootCapabilities['SecureErase'] == true) {
                if (powerState & 2) { addOption('d5actionSelect', "Power up to Secure Erase", 104); }
                if (powerState & 1) { addOption('d5actionSelect', "Reset to Secure Erase", 105); }
            }
            if ((amtPowerBootCapabilities['PlatformErase'] != null) && (amtsysstate['CIM_BootService'] != null) && (amtsysstate['CIM_BootService'].response['EnabledState'] >= 32768) && (amtsysstate['CIM_BootService'].response['EnabledState'] & 2)) {
                if (powerState & 2) { addOption('d5actionSelect', "Power up to Platform Erase", 106); }
                if (powerState & 1) { addOption('d5actionSelect', "Reset to Platform Erase", 107); }
            }
            // ###BEGIN###{IDER}
            if (powerState & 1) { addOption('d5actionSelect', "Reset to IDE-R Floppy", 200); }
            if (powerState & 2) { addOption('d5actionSelect', "Power on to IDE-R Floppy", 201); }
            if (powerState & 1) { addOption('d5actionSelect', "Reset to IDE-R CDROM", 202); }
            if (powerState & 2) { addOption('d5actionSelect', "Power on to IDE-R CDROM", 203); }
            // ###END###{IDER}
            if (powerState & 1) { addOption('d5actionSelect', "Reset to PXE", 400); }
            if (powerState & 2) { addOption('d5actionSelect', "Power on to PXE", 401); }
            // ###BEGIN###{PowerControl-Advanced}
            // ###BEGIN###{PowerControl-OneClick}
            if (amtPowerBootCapabilities['ForceUEFIHTTPSBoot'] === true) {
                if (powerState & 1) { addOption('d5actionSelect', "Reset to HTTPS Boot", 600); }
                if (powerState & 2) { addOption('d5actionSelect', "Power on to HTTPS Boot", 601); }
            }
            // ###END###{PowerControl-OneClick}
            addOption('d5actionSelect', "Custom action...", 999);
            // ###END###{PowerControl-Advanced}
            if (amtversion > 5) { addOption('d5actionSelect', "User consent...", 998); } // On AMT 5 and higher, offer the option of doing user consent alone.
            setDialogMode(5, "Power Actions", 3, powerActionDlgCheck);
        }

        // ###BEGIN###{PowerControl-Advanced}
        // ###BEGIN###{PowerControl-OneClick}
        function oneClickFileSelect() { QE('idx_dlgOkButton', Q('ocrfile').files.length == 1); }
        // ###END###{PowerControl-OneClick}
        // ###END###{PowerControl-Advanced}

        function powerActionDlgCheck() {
            AmtOcrPba = null;
            AmtOcrPbaLength = 0;
            var action = d5actionSelect.value;

            // ###BEGIN###{PowerControl-Advanced}
            // ###BEGIN###{PowerControl-OneClick}
            if ((action == 600) || (action == 601)) {
                // ###BEGIN###{Mode-NodeWebkit}
                // If the connection to intel AMT is not TLS, warn and exit now.
                if (wsstack.comm.xtlsCertificate == null) { messagebox("Power Action", "This feature requires a TLS connection to Intel AMT"); return; }
                // ###END###{Mode-NodeWebkit}
                var x = "Select a disk image for remote boot." + '<br /><br /><input id=ocrfile type=file onchange=oneClickFileSelect() accept=".iso">';
                setDialogMode(11, "HTTPS Boot", 3, function () {
                    var files = Q('ocrfile').files;
                    if (files.length != 1) return;
                    setupWebServer(urlvars['webcn'] ? urlvars['webcn'] : wsstack.comm.localAddress);
                    webserver.setupBootImage(files[0].path, (urlvars['webcn'] ? urlvars['webcn'] : wsstack.comm.localAddress));
                    powerActionDlg();
                }, x);
                QE('idx_dlgOkButton', false);
                return;
            }
            // ###END###{PowerControl-OneClick}
            // ###END###{PowerControl-Advanced}

            if ((action == 500) || (action == 501)) {
                // Perform OS wake from standby or OS sleep (Intel AMT 10+)
                amtstack.RequestOSPowerStateChange((action == 501)?3:2, function (stack, name, response, status) {
                    if (status == 200) { QH('id_dialogMessage', "Power action completed."); } else { QH('id_dialogMessage', format("Power action error #{0}.", status)); }
                    setDialogMode(1, "Power Action", 0);
                    setTimeout(function () { setDialogMode(0); }, 1300);
                });
            } else if ((action == 104) || (action == 105)) {
                var x = ("Confirm execution of Intel&reg; Remote Secure Erase?" + '<br>' + "Enter Secure Erase password if required." + '<br>');
                x += ('<br><div style=height:16px><input type=password id=rsepass maxlength=32 style=float:right;width:240px><div>' + "Password" + '</div></div>');
                x += ('<br><div style=color:red>' + "<b>WARNING:</b> This will wipe data on the remote system." + '</div>');
                // ###BEGIN###{Mode-NodeWebkit}
                if (wsstack.comm.xtlsFingerprint == null) { x += ('<div style=color:red>' + "<b>WARNING:</b> TLS is not used, password will be sent in the clear." + '</div>'); }
                // ###END###{Mode-NodeWebkit}
                rsepass = 1;
                setDialogMode(11, "Power Actions", 3, powerActionDlg, x);
            } else if ((action == 106) || (action == 107)) {
                powerActionDlgRPE();
            // ###BEGIN###{PowerControl-OneClick}
            } else if ((action == 999) && (amtversion >= 15)) {
                statusbox("Power Actions", "Checking boot sources...");            
                amtstack.BatchEnum('', ['CIM_BootSourceSetting'], powerActionDlgCheck00, true);
            // ###END###{PowerControl-OneClick}
            } else {
                powerActionDlg();
            }
        }
        
        function powerActionDlgRPE(advanced) {
            var x = ("Confirm execution of Intel&reg; Remote Platform Erase?" + '<br>');
            x += ('<br><div style=color:red>' + "<b>WARNING:</b> This will wipe data on the remote system." + '</div>');
            var actionTaken = [], platfromEraseSupport = amtPowerBootCapabilities['PlatformErase'];
            if (platfromEraseSupport & (1 << 1)) { actionTaken.push('<label><input id=rpef1 type=checkbox onchange=powerActionDlgRPEValidate()>' + "Pyrite Revert" + '</label>'); }
            if (platfromEraseSupport & (1 << 2)) { actionTaken.push('<label><input id=rpef2 type=checkbox onchange=powerActionDlgRPEValidate()>' + "Secure Erase All SSDs" + '</label>'); }
            if (platfromEraseSupport & (1 << 3)) { actionTaken.push('<label><input id=rpef3 type=checkbox onchange=powerActionDlgRPEValidate()>' + "Verify Storage Erase" + '</label>'); }
            if (platfromEraseSupport & (1 << 6)) { actionTaken.push('<label><input id=rpef6 type=checkbox onchange=powerActionDlgRPEValidate()>' + "TPM Clear" + '</label>'); }
            if (platfromEraseSupport & (1 << 16)) { actionTaken.push('<label><input id=rpef16 type=checkbox onchange=powerActionDlgRPEValidate()>' + "OEM Custom Action" + '</label>'); }
            if (platfromEraseSupport & (1 << 25)) { actionTaken.push('<label><input id=rpef25 type=checkbox onchange=powerActionDlgRPEValidate()>' + "Clear BIOS NVM Variables" + '</label>'); }
            if (platfromEraseSupport & (1 << 26)) { actionTaken.push('<label><input id=rpef26 type=checkbox onchange=powerActionDlgRPEValidate()>' + "BIOS Reload of Golden Configuration" + '</label>'); }
            if (platfromEraseSupport & (1 << 31)) { actionTaken.push('<label><input id=rpef31 type=checkbox onchange=powerActionDlgRPEValidate()>' + "CSME Unconfigure" + '</label>'); }
            if (actionTaken.length > 0) { x += (format('<br />' + "Select the actions to take:" + '<br /><br /><div style=margin-left:16px>{0}</div><br />', actionTaken.join('<br />'))); }
            x += '<div id=rpepsid style=margin-top:4px;margin-bottom:4px;display:none>' + addHtmlValue("Pyrite PSID", '<input id=rpepsidx style=width:210px maxlength=64 type=input>') + '</div>';
            x += '<div id=rpessdpass style=margin-top:4px;margin-bottom:4px;display:none>' + addHtmlValue("SSD Master Password", '<input id=rpessdpassx style=width:210px maxlength=64 type=input>') + '</div>';
            x += '<div id=rpeeomdata style=margin-top:4px;margin-bottom:4px;display:none>' + addHtmlValue("OEM Data (HEX)", '<input id=rpeoemdatax style=width:210px maxlength=256 type=input>') + '</div>';
            setDialogMode(11, "Power Actions", 3, powerActionDlgRPEEx, x, advanced);
            QE('idx_dlgOkButton', false);
        }

        function powerActionDlgRPEValidate() {
            var rpeFlags = 0, platfromEraseSupport = amtPowerBootCapabilities['PlatformErase'], sf = [1, 2, 3, 6, 16, 25, 26, 31];
            for (var i in sf) { if (platfromEraseSupport & (1 << sf[i])) { if (Q('rpef' + sf[i]).checked) { rpeFlags += (1 << sf[i]); } } }
            QV('rpessdpass', rpeFlags & 4);
            QV('rpeeomdata', rpeFlags & (1 << 16));
            QE('idx_dlgOkButton', rpeFlags);
        }

        var platfromEraseTLV = null;
        function powerActionDlgRPEEx(b, advanced) {
            var rpeFlags = 0, platfromEraseSupport = amtPowerBootCapabilities['PlatformErase'], sf = [1, 2, 3, 6, 16, 25, 26, 31];
            for (var i in sf) { if (platfromEraseSupport & (1 << sf[i])) { if (Q('rpef' + sf[i]).checked) { rpeFlags += (1 << sf[i]); } } }
            var tlv = makeUefiBootParam(1, rpeFlags, 4), tlvlen = 1;
            if (rpeFlags & 2) { tlv += makeUefiBootParam(10, Q('rpepsidx').value); tlvlen++; }
            if (rpeFlags & 4) { tlv += makeUefiBootParam(20, Q('rpessdpassx').value); tlvlen++; }
            if ((rpeFlags & (1 << 16)) && (Q('rpeoemdatax').value != '')) { tlv += makeUefiBootParam(20, hex2rstr(Q('rpeoemdatax').value), null, 11); tlvlen++; }
            platfromEraseTLV = { tlv: btoa(tlv), tlvlen: tlvlen };
            if (advanced) {
                // Attempt user consent
                statusbox("Power Action", "Checking state...");
                amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1);
            } else {
                powerActionDlg();
            }
        }

        // ###BEGIN###{PowerControl-OneClick}
        var AmtOcrPba = null;
        var AmtOcrPbaLength = 0;
        function powerActionDlgCheck00(stack, name, response, status) {
            if (status != 200) { messagebox("Power Action", format("GET CIM_BootSourceSetting, Error #{0}", status) + ((response.Header && response.Header.WsmanError) ? (', ' + response.Header.WsmanError) : '')); return; }
            var bootSources = response.CIM_BootSourceSetting.responses;
            AmtOcrPba = {};
            for (var i = 0; i < bootSources.length; i++) {
                var instanceid = bootSources[i]['InstanceID'];
                if ((instanceid != null) && instanceid.toString().startsWith('Intel(r) AMT: Force OCR UEFI Boot')) {
                    try {
                        var arr = instanceid.trim().split(' ');
                        idx = parseInt(arr[arr.length - 1]);
                        AmtOcrPba[parseInt(idx)] = { instance: bootSources[i]['BIOSBootString'], bootstr: bootSources[i]['BootString'] };
                        AmtOcrPbaLength++;
                    } catch (e) { }
                }
            }
            powerActionDlg();
        }
        // ###END###{PowerControl-OneClick}

        function powerActionDlg() {
            //if (amtversion == 0) return;
            //if (amtversion > 6) { amtstack.Get('IPS_OptInService', powerActionResponse0); } else { amtstack.Get('AMT_BootSettingData', powerActionResponse1); }
            var action = d5actionSelect.value;
            // ###BEGIN###{PowerControl-Advanced}
            if (action == 999) { showAdvPowerDlg(); return; }
            // ###END###{PowerControl-Advanced}
            if (action == 998) { amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1); return; }

            // Some actions will not work if KVM/SOL/IDER are connected. If we perform these, disconnect now.
            if ((action < 10) && (action > 2) && (urlvars['noredirdisconnect'] == null)) {
                // ###BEGIN###{Desktop}
                if (desktop.State == 3) connectDesktop();
                // ###END###{Desktop}
                // ###BEGIN###{Terminal}
                if (terminal.State == 3) connectTerminal();
                // ###END###{Terminal}
                // ###BEGIN###{IDER}
                if ((ider != undefined) && (ider.state == 3)) iderStop();
                // ###END###{IDER}
            }

            statusbox("Power Action", "Checking state...");
            if ((rsepass != null) && (rsepass === 1)) { rsepass = Q('rsepass').value; }

            var uc = true; // Check if we need to ask for user consent
            if (amtversion < 6) uc = false; // Below AMT 6, user consent does not exist.
            if ((currentView == 13) && (action == 8)) uc = false; // if in terminal, don't ask for it if power down.
            if ((currentView != 13) && (action <= 10)) uc = false; // if not in terminal, don't ask for basic operations.

            if (uc) {
                // Attempt user consent
                amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1);
            } else {
                // Skip user consent
                amtstack.Get('AMT_BootSettingData', powerActionResponse1, 0, 1);
            }
        }

        // ###BEGIN###{PowerControl-Advanced}
        var AvdPowerDlg;
        function showAdvPowerDlg() {
            try { Q('idx_d24Command').value = (amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'] == 2)?10:2; } catch (ex) { }

            // Available force boot options
            var forceBootDeviceOptions = '<option value=0>None</option><option id="ForceDVDBootOption" value=1>Force CD/DVD Boot</option><option id="ForcePXEBootOption" value=2>Force PXE Boot</option><option id="ForceHDBootOption" value=3>Force Hard Disk Boot</option><option id="ForceDiagBootOption" value=4>Force Diagnostic Boot</option>';

            // Show boot capabilities
            QV('d24dBiosPause', amtPowerBootCapabilities['BIOSPause'] == true);
            QV('d24dBiosSecureBoot', amtPowerBootCapabilities['BIOSSecureBoot'] == true);
            QV('d24dReflashBios', amtPowerBootCapabilities['BIOSReflash'] == true);
            QV('d24dBiosSetup', amtPowerBootCapabilities['BIOSSetup'] == true);
            QV('ForceDVDBootOption', amtPowerBootCapabilities['ForceCDorDVDBoot'] == true);
            QV('ForceDiagBootOption', amtPowerBootCapabilities['ForceDiagnosticBoot'] == true);
            QV('ForceHDBootOption', amtPowerBootCapabilities['ForceHardDriveBoot'] == true);
            //QV('', amtPowerBootCapabilities['ForceHardDriveSafeModeBoot'] == true);
            //QV('', amtPowerBootCapabilities['ForceWinREBoot'] == true);
            QV('ForcePXEBootOption', amtPowerBootCapabilities['ForcePXEBoot'] == true);
            // ###BEGIN###{PowerControl-OneClick}
            if ((AmtOcrPbaLength > 0) && (amtPowerBootCapabilities['ForceUEFIPBABoot'] == true)) {
                forceBootDeviceOptions += '<option id="ForceUEFIBootOption" value=5>Force OCR UEFI Boot Option</option>';
                var x = '';
                for (var i in AmtOcrPba) { x += '<option value=' + i + '>' + AmtOcrPba[i].instance + '</option>'; }
                QH('idx_d24customBootMediaIndex', x);
            }
            var httpsBootPossible = ((meshCentralServer == null) && (wsstack.comm.xtlsCertificate != null)) || (meshCentralServer!=null && ((currentcomputer.conn & 4) == 4) &&  currentcomputer.tls == 1) || (meshCentralServer!=null && ((currentcomputer.conn & 2) == 2) )
            if ((amtPowerBootCapabilities['ForceUEFIHTTPSBoot'] == true) && httpsBootPossible) { forceBootDeviceOptions += '<option id="ForceHttpBootOption" value=6>Force OCR UEFI HTTPS Boot (.iso)</option>'; }
            if ((amtPowerBootCapabilities['ForceUEFIHTTPSBoot'] == true) && httpsBootPossible) { forceBootDeviceOptions += '<option id="ForceHttpUrlBootOption" value=7>Force OCR UEFI HTTPS Boot (url)</option>'; }
            // ###END###{PowerControl-OneClick}
            QV('d24dForceProgressEvents', amtPowerBootCapabilities['ForcedProgressEvents'] == true);
            QV('d24dUseIDER', amtPowerBootCapabilities['IDER'] == true);
            QV('d24dLockKeyboard', amtPowerBootCapabilities['KeyboardLock'] == true);
            QV('d24dLockPowerButton', amtPowerBootCapabilities['PowerButtonLock'] == true);
            QV('d24dLockResetButton', amtPowerBootCapabilities['ResetButtonLock'] == true);
            QV('d24dSerialOverLan', amtPowerBootCapabilities['SOL'] == true);
            QV('d24dSecureErase', amtPowerBootCapabilities['SecureErase'] == true);
            QV('d24dPlatformErase', (amtPowerBootCapabilities['PlatformErase'] != null) && (amtsysstate['CIM_BootService'] != null) && (amtsysstate['CIM_BootService'].response['EnabledState'] >= 32768) && ((amtsysstate['CIM_BootService'].response['EnabledState'] & 2) != 0));
            QV('d24dFirmwareReset', amtPowerBootCapabilities['ConfigurationDataReset'] == true);
            QV('d24dLockSleepButton', amtPowerBootCapabilities['SleepButtonLock'] == true);
            QV('d24dUserPasswordBypass', amtPowerBootCapabilities['UserPasswordBypass'] == true);
            QV('idx_d24Verbocity1', amtPowerBootCapabilities['VerbosityQuiet'] == true);
            QV('idx_d24Verbocity2', amtPowerBootCapabilities['VerbosityVerbose'] == true);
            QV('idx_d24Verbocity3', amtPowerBootCapabilities['VerbosityScreenBlank'] == true);
            QV('d24p500', amtversion > 9);
            QV('d24p501', amtversion > 9);

            QH('idx_d24ForceBootDevice', forceBootDeviceOptions);
            setDialogMode(24, "Custom Power Action", 3, showAdvPowerDlgOk);
            showAdvPowerDlgChange();
        }

        function showAdvPowerDlgChange() {
            var ok = true;
            QV('idd_d24IDERBootDevice', Q('d24UseIDER').checked);
            QV('idd_d24RSEPass', Q('d24SecureErase') ? Q('d24SecureErase').checked : false);
            // ###BEGIN###{Mode-NodeWebkit}
            QV('idd_d24RSEPassTlsWarn', (wsstack.comm.xtlsFingerprint == null) && (Q('d24SecureErase') ? Q('d24SecureErase').checked : false));
            // ###END###{Mode-NodeWebkit}

            // If this is a OS power state change, gray out all of the options.
            var ospower = ((Q('idx_d24Command').value >= 500) && (Q('idx_d24Command').value < 600));
            QE('idx_d24ForceBootDevice', !ospower);
            QE('idx_d24BootMediaIndex', !ospower);
            QE('idd_d24IDERBootDevice', !ospower);
            QE('idx_d24Verbocity', !ospower);
            QE('idd_d24RSEPass', !ospower);

            // If the boot source is not "None" (0), disable all boot settings.
            //var bootSettingOpts = ['d24BiosPause', 'd24BiosSecureBoot', 'd24BiosSetup', 'd24ForceProgressEvents', 'd24LockPowerButton', 'd24LockResetButton', 'd24LockSleepButton', 'd24LockKeyboard', 'd24UserPasswordBypass', 'd24ReflashBios', 'd24SafeMode', 'd24UseIDER', 'd24SerialOverLan', 'd24SecureErase'];
            //if ((idx_d24ForceBootDevice.value > 0) && (idx_d24ForceBootDevice.value < 5)) { for (var i in bootSettingOpts) { Q(bootSettingOpts[i]).checked = false; } }
            //for (var i in bootSettingOpts) { QE(bootSettingOpts[i], idx_d24ForceBootDevice.value == 0); }

            // ###BEGIN###{PowerControl-OneClick}
            var bootSourceIndex = Q('idx_d24ForceBootDevice').value;
            QV('idx_d24bootSource', bootSourceIndex < 5);
            QV('idx_d24customBootSource', bootSourceIndex == 5)
            QV('idx_d24diskImage', bootSourceIndex == 6);
            QV('idx_d24diskImageUrl', bootSourceIndex == 7);
            QV('idx_d24diskImageHttpTimeout', (bootSourceIndex == 7) && (amtversion > 16));
            if ((bootSourceIndex == 6) && (Q('idx_d24ocrBootFile').files.length != 1)) { ok = false; }
            if ((bootSourceIndex == 7) && (Q('idx_d24ocrBootUrl').value.trim().toLowerCase().startsWith('https://') == false)) { ok = false; }
            if ((bootSourceIndex == 7) && (amtversion > 16)) {
                var timeout = parseInt(Q('idx_d24ocrBootHttpBootTimeout').value);
                if (isNaN(timeout) || (timeout > 65535) || (timeout < 0)) { ok = false; }
            }
            // ###END###{PowerControl-OneClick}

            QE('idx_dlgOkButton', ok);
        }

        function showAdvPowerDlgOk() {
            // ###BEGIN###{PowerControl-OneClick}
            var forceBootSelection = Q('idx_d24ForceBootDevice').value;
            // ###BEGIN###{Mode-NodeWebkit}            
            if (((forceBootSelection == 5) || (forceBootSelection == 6) || (forceBootSelection == 7)) && 
                (((meshCentralServer == null) && (wsstack.comm.xtlsCertificate == null)) || (meshCentralServer!=null && ((currentcomputer.conn & 4) == 4) &&  currentcomputer.tls == 0))) {
                messagebox("Power Action", "This feature requires a TLS connection to Intel AMT"); return;
            }
            // ###END###{Mode-NodeWebkit}
            if (forceBootSelection == 6) {
                var files = Q('idx_d24ocrBootFile').files;
                if (files.length == 1) {
                    setupWebServer(urlvars['webcn'] ? urlvars['webcn'] : wsstack.comm.localAddress);
                    webserver.setupBootImage(files[0].path, (urlvars['webcn'] ? urlvars['webcn'] : wsstack.comm.localAddress));
                }
            }
            // ###END###{PowerControl-OneClick}

            var action = Q('idx_d24Command').value;
            if ((action == 500) || (action == 501)) {
                // Perform OS wake from standby or OS sleep (Intel AMT 10+)
                amtstack.RequestOSPowerStateChange((action == 501) ? 3 : 2, function (stack, name, response, status) {
                    if (status == 200) { QH('id_dialogMessage', "Power action completed."); } else { QH('id_dialogMessage', format("Power action error #{0}.", status)); }
                    setDialogMode(1, "Power Action", 0);
                    setTimeout(function () { setDialogMode(0); }, 1300);
                });
            } else {
                // Fetch all of the user data
                AvdPowerDlg = {};
                AvdPowerDlg.Action = Q('idx_d24Command').value;
                AvdPowerDlg.BIOSPause = Q('d24BiosPause').checked;
                AvdPowerDlg.BIOSSecureBoot = Q('d24BiosSecureBoot').checked;
                AvdPowerDlg.BIOSSetup = Q('d24BiosSetup').checked;
                AvdPowerDlg.BootMediaIndex = Q('idx_d24BootMediaIndex').value;
                AvdPowerDlg.FirmwareVerbosity = Q('idx_d24Verbocity').value;
                AvdPowerDlg.ForcedProgressEvents = Q('d24ForceProgressEvents').checked;
                AvdPowerDlg.IDERBootDevice = Q('idx_d24IDERBootDevice').value; // 0 = Boot on Floppy, 1 = Boot on IDER
                AvdPowerDlg.LockKeyboard = Q('d24LockKeyboard').checked;
                AvdPowerDlg.LockPowerButton = Q('d24LockPowerButton').checked;
                AvdPowerDlg.LockResetButton = Q('d24LockResetButton').checked;
                AvdPowerDlg.LockSleepButton = Q('d24LockSleepButton').checked;
                AvdPowerDlg.ReflashBIOS = Q('d24ReflashBios').checked;
                AvdPowerDlg.UseIDER = Q('d24UseIDER').checked;
                AvdPowerDlg.UseSOL = Q('d24SerialOverLan').checked;
                AvdPowerDlg.UseSafeMode = Q('d24SafeMode').checked;
                AvdPowerDlg.UserPasswordBypass = Q('d24UserPasswordBypass').checked;
                AvdPowerDlg.SecureErase = Q('d24SecureErase').checked;
                AvdPowerDlg.PlatformErase = Q('d24PlatformErase').checked
                AvdPowerDlg.FirmwareReset = Q('d24FirmwareReset').checked;
                if ((AvdPowerDlg.SecureErase === true) && (Q('d24rsepass').value.length > 0)) { AvdPowerDlg.RSEPassword = Q('d24rsepass').value; }

                if (AvdPowerDlg.PlatformErase === true) {
                    // Ask additional information about RPE
                    powerActionDlgRPE(true);
                } else {
                    // Attempt user consent
                    statusbox("Power Action", "Checking state...");
                    amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1);
                }
            }
        }
        // ###END###{PowerControl-Advanced}

        function powerActionResponse0(stack, name, response, status) {
            //if (errcheck(status, stack)) return; // TODO: If AMT 5 or below, this will error and we need to skip user consent.
            if (status != 200) {
                if (connectDesktopConsent) { connectDesktop(true); } else { messagebox("Power Action", format("Error #{0}", status)); }
                return;
            }
            //console.log('powerActionResponse0(' + name + ',' + ObjectToString2(response) + ',' + status + ')');
            //console.log("OptInRequired:", response.Body['OptInRequired']);
            //console.log("OptInState:", response.Body['OptInState']);
            //console.log(response);
            if (((response.Body['OptInRequired'] == 0xFFFFFFFF) || (connectDesktopConsent && (response.Body['OptInRequired'] != 0))) && (response.Body['OptInState'] != 3) && (response.Body['OptInState'] != 4)) {
                if (response.Body['OptInState'] == 2) {
                    amtstack.IPS_OptInService_CancelOptIn(null);
                    d6ConsentText.value = ''; // Reset user consent code to empty
                    setDialogMode(6, "User Consent", 11, powerActionSendConsent);
                    checkConsentDisplay();
                    consentChanged();
                    return;
                }
                //console.log("Opt-in Required.", response.Body['OptInRequired']);
                statusbox("Power Action", "Starting opt-in...");
                amtstack.IPS_OptInService_StartOptIn(powerActionResponseC1, 0, 1);
            } else {
                if (connectDesktopConsent) { setDialogMode(0); connectDesktop(true); return; }
                if (d5actionSelect.value == 998) { messagebox("User Consent", "User consent not needed."); return; }
                statusbox("Power Action", "Getting Boot Settings...");
                amtstack.Get('AMT_BootSettingData', powerActionResponse1, 0, 1);
            }
        }

        function powerActionResponseC1(stack, name, response, status) {
            //if (errcheck(status, stack)) return;
            //console.log('powerActionResponseC1', name, status, response);
            if (status != 200) { if (connectDesktopConsent) { setDialogMode(0); connectDesktop(true); } else { messagebox("Power Action", format("Error #", status)); } return; }
            //console.log("powerActionResponseC1(" + name + "," + ObjectToString2(response) + "," + status + ")");
            if (response.Body['ReturnValue'] != 0) {
                if (connectDesktopConsent) { setDialogMode(0); connectDesktop(true); } else { messagebox("User Consent Error", response.Body.ReturnValueStr.replace(/_/g, ' ')); }
            } else {
                d6ConsentText.value = ''; // Reset user consent code to empty
                setDialogMode(6, "User Consent", 11, powerActionSendConsent);
                checkConsentDisplay();
                consentChanged();

                // Check if the machine is powered down, if it is, power it up for user consent.
                amtstack.Enum('CIM_ServiceAvailableToElement', function(stack, name, responses, status) {
                    if (errcheck(status, stack)) return;
                    amtsysstate['CIM_ServiceAvailableToElement'].responses = responses;
                    updateSystemStatus();
                    if ((amtsysstate['CIM_ServiceAvailableToElement'] != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses != null) && (amtsysstate['CIM_ServiceAvailableToElement'].responses.length > 0)) {
                        if (amtsysstate['CIM_ServiceAvailableToElement'].responses[0]['PowerState'] != 2) {
                            // System is not on, power it on now.
                            amtstack.RequestPowerStateChange(2, function (stack, name, response, status) { });
                        }
                    }
                });
            }
        }

        //function powerActionCancelConsent() { amtstack.IPS_OptInService_CancelOptIn(null); }

        function powerActionSendConsent(buttons) {
            console.log('powerActionSendConsent', buttons);
            if (buttons == 0) {
                // Cancel button
                amtstack.IPS_OptInService_CancelOptIn(function () { });
                connectDesktopConsent = false;
                desktop.Stop();
            } else {
                // OK Button
                statusbox("Power Action", "Sending user consent...");
                amtstack.IPS_OptInService_SendOptInCode(d6ConsentText.value, powerActionResponseC2, 0, 1);
            }
        }

        function powerActionResponseC2(stack, name, response, status) {
            //if (errcheck(status, stack)) return;
            if (status != 200) { messagebox("Power Action", format("Error #{0}", status)); return; }
            //console.log("powerActionResponseC2(" + name + "," + ObjectToString2(response) + "," + status + ")");
            if (response.Body['ReturnValue'] != 0) {
                amtstack.Get('IPS_OptInService', powerActionResponse0, 0, 1);
            } else {
                if (connectDesktopConsent) { setDialogMode(0); connectDesktop(true); return; }
                if (d5actionSelect.value == 998) { messagebox("User Consent", "User consent succesful."); return; } // This was just a user consent request, no need to go further.
                statusbox("Power Action", "Checking state...");
                amtstack.Get('AMT_BootSettingData', powerActionResponse1, 0, 1);
            }
        }

        function powerActionResponse1(stack, name, response, status) {
            //if (errcheck(status, stack)) return;
            if (status != 200) { messagebox("Power Action", format("Error #{0}", status)); return; }
            //console.log("powerActionResponse1(" + name + "," + ObjectToString2(response) + "," + status + ")");
            var action = d5actionSelect.value;
            var r = response.Body;
            r['ConfigurationDataReset'] = false;

            // Clean up parameters
            delete r['WinREBootEnabled'];
            delete r['UEFILocalPBABootEnabled'];
            delete r['UEFIHTTPSBootEnabled'];
            delete r['SecureBootControlEnabled'];
            delete r['BootguardStatus'];
            delete r['OptionsCleared'];
            delete r['BIOSLastStatus'];
            delete r['UefiBootParametersArray'];
            delete r['RPEEnabled'];

            // ###BEGIN###{PowerControl-Advanced}
            if (action == 999) {
                r['BIOSPause'] = AvdPowerDlg.BIOSPause;
                r['EnforceSecureBoot'] = AvdPowerDlg.BIOSSecureBoot;
                r['BIOSSetup'] = AvdPowerDlg.BIOSSetup;
                r['BootMediaIndex'] = AvdPowerDlg.BootMediaIndex;
                r['FirmwareVerbosity'] = AvdPowerDlg.FirmwareVerbosity;
                r['ForcedProgressEvents'] = AvdPowerDlg.ForcedProgressEvents;
                r['IDERBootDevice'] = AvdPowerDlg.IDERBootDevice; // 0 = Boot on Floppy, 1 = Boot on IDER
                r['LockKeyboard'] = AvdPowerDlg.LockKeyboard;
                r['LockPowerButton'] = AvdPowerDlg.LockPowerButton;
                r['LockResetButton'] = AvdPowerDlg.LockResetButton;
                r['LockSleepButton'] = AvdPowerDlg.LockSleepButton;
                r['ReflashBIOS'] = AvdPowerDlg.ReflashBIOS;
                r['UseIDER'] = AvdPowerDlg.UseIDER;
                r['UseSOL'] = AvdPowerDlg.UseSOL;
                r['UseSafeMode'] = AvdPowerDlg.UseSafeMode;
                r['UserPasswordBypass'] = AvdPowerDlg.UserPasswordBypass;
                if (r['SecureErase'] != null) {
                    r['SecureErase'] = ((AvdPowerDlg.SecureErase) && (amtPowerBootCapabilities['SecureErase'] == true));
                    if ((r['SecureErase'] == true) && (AvdPowerDlg.RSEPassword)) { r['RSEPassword'] = AvdPowerDlg.RSEPassword; }
                }
                if (r['PlatformErase'] != null) {
                    if ((amtsysstate['CIM_BootService'] != null) && (amtsysstate['CIM_BootService'].response['EnabledState'] >= 32768) && (amtsysstate['CIM_BootService'].response['EnabledState'] & 2) && ((AvdPowerDlg.PlatformErase) && (amtPowerBootCapabilities['PlatformErase'] != null) && ((amtPowerBootCapabilities['PlatformErase'] & 1) != 0))) {
                        r['PlatformErase'] = true;
                        r['UefiBootParametersArray'] = platfromEraseTLV.tlv;
                        r['UefiBootNumberOfParams'] = platfromEraseTLV.tlvlen;
                    } else {
                        r['PlatformErase'] = false;
                    }
                }
                if (r['ConfigurationDataReset'] != null) { r['ConfigurationDataReset'] = AvdPowerDlg.FirmwareReset; }
            } else {
                // ###END###{PowerControl-Advanced}
                r['BIOSPause'] = false;
                r['EnforceSecureBoot'] = false;
                r['BIOSSetup'] = (action > 99 && action < 104);
                r['BootMediaIndex'] = 0;
                r['FirmwareVerbosity'] = 0;
                r['ForcedProgressEvents'] = false;
                r['IDERBootDevice'] = ((action == 202) || (action == 203))?1:0; // 0 = Boot on Floppy, 1 = Boot on IDER
                r['LockKeyboard'] = false;
                r['LockPowerButton'] = false;
                r['LockResetButton'] = false;
                r['LockSleepButton'] = false;
                r['ReflashBIOS'] = false;
                r['UseIDER'] = ((action > 199) && (action < 300));
                //r['UseSOL'] = ((currentView == 13) && (action != 8) && (action != 300) && (action != 301)); // If we are looking at the terminal, turn on SOL. SOL can't be used with diagnostic mode (300/301)
                r['UseSOL'] = ((currentView == 13) && (action != 8) && (action < 300)); // If we are looking at the terminal, turn on SOL.
                r['UseSafeMode'] = false;
                r['UserPasswordBypass'] = false;
                if (r['SecureErase'] != null) {
                    r['SecureErase'] = (((action == 104) || (action == 105)) && (amtPowerBootCapabilities['SecureErase'] == true));
                    if ((r['SecureErase'] === true) && (rsepass.length > 0)) { r['RSEPassword'] = rsepass; }
                }
                if (r['PlatformErase'] != null) {
                    if ((amtsysstate['CIM_BootService'] != null) && (amtsysstate['CIM_BootService'].response['EnabledState'] >= 32768) && (amtsysstate['CIM_BootService'].response['EnabledState'] & 2) && (((action == 106) || (action == 107)) && (amtPowerBootCapabilities['PlatformErase'] != null) && (((amtPowerBootCapabilities['PlatformErase'] & 1)) != 0))) {
                        r['PlatformErase'] = true;
                        r['UefiBootParametersArray'] = platfromEraseTLV.tlv;
                        r['UefiBootNumberOfParams'] = platfromEraseTLV.tlvlen;
                    } else {
                        r['PlatformErase'] = false;
                    }
                }
                if (r['ConfigurationDataReset'] != null) { r['ConfigurationDataReset'] = false; }
                rsepass = null;
                // ###BEGIN###{PowerControl-Advanced}
            }

            // ###BEGIN###{PowerControl-OneClick}
            // Add OCR TLV parameters if firmware supports OCR and Force HTTPS Boot is requested
            if ((action == 999) && (Q('idx_d24ForceBootDevice').value == 7)) { // Force UEFI HTTPS Boot using URL
                const bootUrl = new URL(Q('idx_d24ocrBootUrl').value.trim());
                const bootUrlUsername = bootUrl.username;
                const bootUrlPassword = bootUrl.password;
                bootUrl.username = bootUrl.password = '';
                var uefiParams = makeUefiBootParam(1, bootUrl.href) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2);
                if (bootUrlUsername != '') { uefiParams += makeUefiBootParam(40, bootUrlUsername); } // HTTP basic auth username
                if (bootUrlPassword != '') { uefiParams += makeUefiBootParam(41, bootUrlPassword); } // HTTP basic auth password
                if (amtversion > 16) {
                    var timeout = parseInt(Q('idx_d24ocrBootHttpBootTimeout').value);
                    if (timeout > 0) { uefiParams += makeUefiBootParam(30, timeout, 2); }
                }
                r['UefiBootParametersArray'] = btoa(uefiParams);
                r['UefiBootNumberOfParams'] = 3;
                r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
            } else if ((action == 600) || (action == 601) || ((action == 999) && (Q('idx_d24ForceBootDevice').value == 6))) { // Force UEFI HTTPS Boot
                // Check if using built-in webserver or external webserver
                r['UefiBootParametersArray'] = webserver.lastBootImageArgs.args;
                r['UefiBootNumberOfParams'] = webserver.lastBootImageArgs.argscount;
                r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
            } else if ((action == 999) && (Q('idx_d24ForceBootDevice').value == 5)) {
                var bootstr = AmtOcrPba[Q('idx_d24customBootMediaIndex').value].bootstr;
                console.log('OCR BootStr: ' + bootstr);
                r['UefiBootParametersArray'] = btoa(makeUefiBootParam(2, bootstr) + makeUefiBootParam(3, bootstr.length, 2)); // EFI_DEVICE_PATH (2) + EFI_DEVICE_PATH-LENGTH (3)
                r['UefiBootNumberOfParams'] = 2;
                r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
            }
            // ###END###{PowerControl-OneClick}
            // ###END###{PowerControl-Advanced}

            //if (((action == 104) || (action == 105)) && !r['SecureErase']) { /*console.log("This Intel&reg; AMT does not support Secure Erase");*/ cleanup(); return; }
            console.log("Boot Action: " + action);
            console.log("Setting Boot Settings: " + ObjectToString2(r));
            statusbox("Power Action", "Setting boot settings...");

            // Set the boot order to null, this is needed for some AMT versions that don't clear this automatically.
            amtstack.CIM_BootConfigSetting_ChangeBootOrder(null, function (stack, name, response, status) {
                if (status != 200) { messagebox("Power Action", format("PUT CIM_BootConfigSetting_ChangeBootOrder, Error #{0}", status) + ((response.Header && response.Header.WsmanError) ? (', ' + response.Header.WsmanError) : '')); return; }
                if (response.Body['ReturnValue'] != 0) { messagebox("Change Boot Order", "(1) Change Boot Order returns "+ response.Body.ReturnValueStr); return; }
                amtstack.Put('AMT_BootSettingData', r, powerActionResponse2, 0, 1);
            }, 0, 1);
        }

        function powerActionResponse2(stack, name, response, status, tag) {
            //console.log("powerActionResponse2(" + name + "," + response + "," + status + ")");
            if (status != 200) { messagebox("Power Action", format("PUT AMT_BootSettingData, Error #{0}", status) + ((response.Header && response.Header.WsmanError) ? (', ' + response.Header.WsmanError) : '')); return; }
            //if (status == 408) { messagebox("Power Action", "Access denied."); return; }
            //if (errcheck(status, stack)) return;
            //console.log("Setup next boot...");
            statusbox("Power Action", "Setting next boot...");
            amtstack.SetBootConfigRole(1, powerActionResponse3x, 0, 1);
        }

        function powerActionResponse3x(stack, name, response, status) {
            //console.log("powerActionResponse3x(" + name + "," + response + "," + status + ")");
            var action = d5actionSelect.value, bootSource = null;
            // ###BEGIN###{PowerControl-Advanced}
            if (action == 999) {
                // ###BEGIN###{!PowerControl-OneClick}
                if (idx_d24ForceBootDevice.value > 0) { bootSource = ['Force CD/DVD Boot', 'Force PXE Boot', 'Force Hard-drive Boot', 'Force Diagnostic Boot'][idx_d24ForceBootDevice.value - 1]; }
                // ###END###{!PowerControl-OneClick}
                // ###BEGIN###{PowerControl-OneClick}
                if (idx_d24ForceBootDevice.value > 0) { bootSource = ['Force CD/DVD Boot', 'Force PXE Boot', 'Force Hard-drive Boot', 'Force Diagnostic Boot', 'Force OCR UEFI Boot Option ' + Q('idx_d24customBootMediaIndex').value, 'Force OCR UEFI HTTPS Boot', 'Force OCR UEFI HTTPS Boot'][idx_d24ForceBootDevice.value - 1]; }
                // ###END###{PowerControl-OneClick}
            } else {
            // ###END###{PowerControl-Advanced}
                if (action == 300 || action == 301) { bootSource = 'Force Diagnostic Boot'; }
                if (action == 400 || action == 401) { bootSource = 'Force PXE Boot'; }
            // ###BEGIN###{PowerControl-Advanced}
                if (action == 600 || action == 601) { bootSource = 'Force OCR UEFI HTTPS Boot'; }
            }

            // Resetting Force boot data in case it was changed so that it won't be used on the next power action
            Q('idx_d24ForceBootDevice').value = 0;

            // ###END###{PowerControl-Advanced}
            console.log('ChangeBootOrder: ' + bootSource);
            amtstack.CIM_BootConfigSetting_ChangeBootOrder((bootSource == null)?bootSource:'<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: ' + bootSource + '</Selector></SelectorSet></ReferenceParameters>', powerActionResponse3);
        }

        var targetPowerAction = 0;
        function powerActionResponse3(stack, name, response, status) {
            //console.log('powerActionResponse3(' + name + ',' + response + ',' + status + ')');
            if (errcheck(status, stack)) return;
            if (response.Body['ReturnValue'] != 0) { messagebox("Change Boot Order", "(2) Change Boot Order returns "+ response.Body.ReturnValueStr); return; }

            //console.log("Performing Power State Change...");
            statusbox("Power Action", "Performing power action...");
            var action = d5actionSelect.value;
            if (action == 100 || action == 201 || action == 203 || action == 300 || action == 401 || action == 601) action = 2; // Power up
            if (action == 101 || action == 200 || action == 202 || action == 301 || action == 400 || action == 600) action = 10; // Reset
            if (action == 104) action = 2; // Power on with Remote Secure Erase
            if (action == 105) action = 10; // Reset with Remote Secure Erase
            if (action == 106) action = 2; // Power on with Remote Platfrom Erase
            if (action == 107) action = 10; // Reset with Remote Platfrom Erase
            // ###BEGIN###{PowerControl-Advanced}
            if (action == 999) action = AvdPowerDlg.Action;
            targetPowerAction = action;
            //console.log('RequestPowerStateChange:' + action);
            if (action == 11) { action = 10; }
            if (action < 999) { console.log('RequestPowerStateChange(' + action + ')'); amtstack.RequestPowerStateChange(action, powerActionResponse4); } else { messagebox("Power Action", "Next boot action set."); }
            // ###END###{PowerControl-Advanced}
            // ###BEGIN###{!PowerControl-Advanced}
            targetPowerAction = action;
            amtstack.RequestPowerStateChange(action, powerActionResponse4);
            // ###END###{!PowerControl-Advanced}
        }

        function powerActionResponse4(stack, name, response, status) {
            //console.log("powerActionResponse4(" + name + "," + response + "," + status + ")");
            if (status == 200) {
                // Done!
                //console.log("Action Completed.");
                QH('id_dialogMessage', "Power action completed.");
                setDialogMode(1, "Power Action", 0);
                setTimeout(function() { setDialogMode(0); }, 1300);
            }
            // console.log("Power State Error: " + status);
            // Sometimes Intel AMT with not respond and this will timeout. Try to pull the power state
            amtstack.Get('CIM_AssociatedPowerManagementService', powerActionResponse5, 0, 1);
        }

        function powerActionResponse5(stack, name, response, status) {
            //console.log("powerActionResponse5(" + name + "," + response + "," + status + ")");
            /*
            if (errcheck(status, stack)) return;
            var powerstate = parseInt(response.Body['PowerState']);
            console.log("powerstate: " + powerstate);
            if (targetPowerAction == powerstate) {
                console.log("Action Completed. ");
            } else {
                console.log("Power State Error: " + status + ", CurrentState=" + powerstate + ", TargetState=" + targetPowerAction);
            }
            */
        }

        function consentChanged() { QE('idx_dlgOkButton', d6ConsentText.value.length == 6); }
        function changeConsentDisplay() { xxchangeConsentDisplay = true; checkConsentDisplay(); }
        function checkConsentDisplay() { /*console.log("Getting display information...");*/ amtstack.Get('IPS_SecIOService', checkConsentDisplayResponse1); }

        var xxchangeConsentDisplay = false;
        function checkConsentDisplayResponse1(stack, name, response, status) {
            // console.log('checkConsentDisplayResponse1(' + name + ',' + response + ',' + status + ')');
            if (status == 200) {
                if (response.Body['DefaultScreen']) response.Body['DefaultScreen'] = parseInt(response.Body['DefaultScreen']);
                if (response.Body['NumberOfScreens']) response.Body['NumberOfScreens'] = parseInt(response.Body['NumberOfScreens']);
                if (xxchangeConsentDisplay == true) {
                    xxchangeConsentDisplay = false;
                    // Change consent screen settings
                    response.Body['DefaultScreen'] = d6Display.value;
                    amtstack.Put('IPS_SecIOService', response.Body, checkConsentDisplayResponse1);
                } else {
                    d6Display.value = response.Body['DefaultScreen'];
                    QV('d6ThirdDisplay', response.Body['NumberOfScreens'] > 2);
                }
            } else {
                //console.log("Display Error: " + status);
            }
        }

// ###END###{PowerControl}

// ###BEGIN###{Storage}

        //
        // Storage
        //

        var xxStorage = null;
        var xxStorageVendors = [];
        var xxStorageApplications = [];

        function PullStorage() {
            amtFirstPull |= 8;
            wsstack.comm.PerformAjax('', PullStorageResponse, null, 0, '/amt-storage/', 'GET');
        }

        function PullStorageResponse(data, status, tag) {
            if (amtstack.PendingBatchOperations == 0) refreshButtons(true); // If nothing is being done, re-enable refresh buttons
            
            if (status == 200) {
                QV('go21', true); // Show Storage Panel

                var len; // Remove all chars that are below 32, this will allow parsing even the the firmware gives us garbage.
                for (var i = 0; i < 32; i++) { do { len = data.length; data = data.replace(String.fromCharCode(i), ''); } while (len > data.length); }
                //data = '{"information": {"version": 1.1,"realms": 7765759,"user": "admin"},"content": [{"name": "index.htm","size": 38864},{"vendor": "User","app": "SDK","name": "Sample.html","size": 26760,"link": "SDK Sample"},{"vendor": "User","app": "SDK","name": "ws.js","size": 42575,"link": "SDK Sample"},{"vendor": "User","app": "SDK","name": "btp.min.css","size": 121265,"link": "SDK Sample"},{"vendor": "User","app": "SDK","name": "logo.png","size": 2803,"link": "SDK Sample"}]}';
                try { xxStorage = JSON.parse(data); } catch (e) { return; }
                xxStorageVendors = [];
                xxStorageApplications = [];
                var content = xxStorage['content'];

                if (Array.isArray(content)) {
                    // New flat format, convert to tree format.
                    var newcontent = {};
                    for (var i in content) {
                        var vendor = content[i]['vendor'] ? content[i]['vendor'] : '';
                        if (!newcontent[vendor]) { newcontent[vendor] = {}; }
                        var app = content[i]['app'] ? content[i]['app'] : '';
                        if (!newcontent[vendor][app]) { newcontent[vendor][app] = {}; }
                        if (content[i]['name']) { newcontent[vendor][app][content[i]['name']] = content[i]; }
                    }
                    xxStorage['content'] = content = newcontent;
                } else {
                    // Tree format, move index.htm and logon.htm
                    if (content['index.htm'] || content['logon.htm']) { content[''] = { '': {} }; }
                    if (content['index.htm']) { content['']['']['index.htm'] = content['index.htm']; delete content['index.htm']; }
                    if (content['logon.htm']) { content['']['']['logon.htm'] = content['logon.htm']; delete content['logon.htm']; }
                }

                // Display all storage files
                var count = 0, x = TableStart2() + '<tr><td class=r1 style=padding-left:15px><br>' + "Manage Intel&reg; AMT storage for this computer." + '<br><br>';
                var ii, jj, xx = '', links = '', linkid = 30;
                for (var i in content) {
                    var jcount = 0;
                    for (var j in content[i]) {
                        jcount++;
                        var kcount = 0;
                        for (var k in content[i][j]) {
                            kcount++;
                            if (i != ii || j != jj) {
                                if (xx != '') { x += xx; xx = '<br>'; }
                                ii = i; jj = j;
                                if (i != '') { xx += EscapeHtml(i + ' / ' + j); } else { xx += "Root"; }
                            }
                            //var handle = "\"" + i + "\",\"" + j + "\",\"" + k + "\"";
                            var handle = '\"' + i + ((i != '') ? '/' : '') + j + ((j != '') ? '/' : '') + k + '\"';
                            xx += '<div class=itemBar onclick=showStorageDetails("' + i + '","' + j + '","' + k + '",' + handle + ')><div style=float:right>';
                            // ###BEGIN###{Mode-Firmware}
                            xx += AddButton2("Open", 'OpenFromStorage(' + handle + ',event)');
                            // ###END###{Mode-Firmware}
                            // ###BEGIN###{Mode-LMS}
                            xx += ' ' + AddButton2("Open", 'OpenFromStorage(' + handle + ',event)');
                            // ###END###{Mode-LMS}
                            // ###BEGIN###{FileSaver}
                            xx += ' ' + AddButton2("Download", 'DownloadFromStorage(' + handle + ',\"' + k + '\",event)');
                            // ###END###{FileSaver}
                            xx += '</div><div style=padding-top:3px><b>' + EscapeHtml(k) + '</b>, <i>' + content[i][j][k]['size'] + " bytes" + '</i></div></div>';
                            // ###BEGIN###{Mode-Firmware}
                            if (content[i][j][k]['link'] && i != '') { links += '<p id=go' + linkid + ' class=nav1 onclick=goiFrame(event,' + linkid + ',"/amt-storage/' + i + '/' + j + '/' + k + '") title="' + i + ' / ' + j + '"><a>' + content[i][j][k]['link'] + '</a></p>'; linkid++; }
                            // ###END###{Mode-Firmware}
                            count++;
                            if (xxStorageVendors.indexOf(i) == -1) xxStorageVendors.push(i);
                            if (xxStorageApplications.indexOf(j) == -1) xxStorageApplications.push(j);
                        }
                        if (kcount == 0) {  // Clear empty application & vendor
                            wsstack.comm.PerformAjax('', function () { }, null, 0, '/amt-storage/' + i + '/' + j, 'DELETE');
                            wsstack.comm.PerformAjax('', function () { }, null, 0, '/amt-storage/' + i, 'DELETE');
                        }
                    }
                    if (jcount == 0) { wsstack.comm.PerformAjax('', function () { }, null, 0, '/amt-storage/' + i, 'DELETE'); } // Clear empty vendor
                }
                if (xx != '') x += xx;
                if (count == 0) { x += '<div style=padding-left:15px><br><i>' + "No files found." + '</i></div><br>'; }
                var uploadSupport = false;
                try { var reader = new FileReader(); uploadSupport = ((reader != null) && (reader.readAsBinaryString != null)); } catch (ex) { console.log(ex); }
                x += '<br><td class=r1>' + TableEnd(AddRefreshButton('PullStorage()') + (uploadSupport ? AddButton("Upload...", 'UploadToStorage()') : '')
                // ###BEGIN###{Mode-NodeWebkit}
                    //+ AddButton("Upload Application...", 'UploadAppToStorage()')
                // ###END###{Mode-NodeWebkit}
                );
                // ###BEGIN###{Mode-Firmware}
                //QH('storagelinks', links);
                // ###END###{Mode-Firmware}
                QH('id_TableSystemStorage', x);
            } else {
                QH('id_TableSystemStorage', "Unable to load storage data..." + '<br/>' + AddButton("Refresh", 'PullStorage()'));
            }
        }

        function showStorageDetails(i, j, k, h) {
            if (xxdialogMode) return;
            var x = '', item = xxStorage['content'][i][j][k];
            if (i != '') x += addHtmlValue("Vendor", i);
            if (j != '') x += addHtmlValue("Application", j);
            x += addHtmlValue("Name", k);
            x += addHtmlValue("Size", item['size'] + ' bytes');
            if (item['link']) { x += addHtmlValue("Link", item['link']); }
            setDialogMode(11, "Storage Item", 5, showStorageDetailsEx, x, h);
        }

        function showStorageDetailsEx(buttons, handle) {
            if (buttons == 2) { wsstack.comm.PerformAjax('', storageDeleteResponse, null, 0, '/amt-storage/' + handle, 'DELETE'); }
        }

        function storageDeleteResponse(data, status) {
            if (status != 200) {
                messagebox("Storage", format("Unable to delete file (ERR{0}), check that the computer is powered on.", status));
            } else {
                PullStorage();
            }
        }

        // ###BEGIN###{FileSaver}
        function DownloadFromStorage(handle, filename, e) {
            if (xxdialogMode) return;
            haltEvent(e);
            wsstack.comm.PerformAjax('', DownloadFromStorageEx, filename, 0, '/amt-storage/' + handle, 'GET');
        }

        function DownloadFromStorageEx(data, status, tag) {
            if ((status != 200) || (data == null)) { console.log(status, 'Data = null'); return; }
            saveAs(data2blob(data), tag);
        }
        // ###END###{FileSaver}

        function OpenFromStorage(handle, e) {
            if (xxdialogMode) return;
            haltEvent(e);
            // ###BEGIN###{Mode-Firmware}
            var newWindow = window.open('/amt-storage/' + handle, '_blank', 'noopener,noreferrer');
            // ###END###{Mode-Firmware}
            // ###BEGIN###{!Mode-Firmware}
            var newWindow = window.open('http://' + wsstack.comm.host + ':' + wsstack.comm.port + '/amt-storage/' + handle, '_blank', 'noopener,noreferrer');
            // ###END###{!Mode-Firmware}
            newWindow.opener = null;
            newWindow.focus();
        }

        function PushToStorage(vendorAppnameFilename, data, append) {
            var tag = null;
            if (data.length > 7000) { tag = [vendorAppnameFilename, data.substring(7000)]; data = data.substring(0, 7000); }
            wsstack.comm.PerformAjax(data, PushToStorageResponse, tag, 0, '/amt-storage/' + vendorAppnameFilename + (append == true ? '?append=' : ''), 'PUT');
        }

        function PushToStorageResponse(data, status, tag) {
            if (status != 200) { messagebox("Storage", format("Unable to push file (ERR{0}), check that the computer is powered on.", status)); } else {
                if (tag != null) { PushToStorage(tag[0], tag[1], true); } else { PullStorage(); }
            }
        }

        function UploadToStorage(file, filename) {
            if (xxdialogMode) return;
            if (!filename) { filename = ''; }
            var x = '';
            x += '<br>' + "Select a small file to upload to storage and enter a vendor, application and filename." + '<br>';
            if (!file) {
                x += '<br><div style=height:20px><input type=file id=mstoragefile style=float:right;width:240px onchange=SetStorageName()><div>Upload file</div></div>';
            } else {
                x += '<br><div style=height:20px><input id=mstoragefile style=float:right;width:240px readonly disabled=disabled value="' + filename + '" ><div>' + "Upload file" + '</div></div>';
            }
            x += '<br><div style=height:16px><input id=mstoragevendor placeholder="' + "Vendor" + '" list=mstoragevendorlist maxlength=11 style=float:right;width:240px><div>' + "Vendor name" + '</div></div>';
            x += '<br><div style=height:16px><input id=mstorageapplication placeholder="' + "App" + '" list=mstorageapplicationlist maxlength=11 style=float:right;width:240px><div>' + "Application name" + '</div></div>';
            x += '<br><div style=height:16px><input id=mstoragefilename placeholder="' + "Filename" + '" maxlength=11 style=float:right;width:240px><div>' + "Filename" + '</div></div>';
            x += '<br><div style=height:16px><input id=mstoragetype placeholder=application/octet-stream list=mstoragetypelist style=float:right;width:240px><div>' + "MIME Type" + '</div></div>';
            x += '<br><div style=height:16px><input id=mstoragelink style=float:right;width:240px><div title=\"' + "If set, creates a link to this content from the main web page" + '\">' + "Link" + '</div></div><br>';
            x += '<datalist id=mstoragevendorlist>';
            for (var i in xxStorageVendors) { x += '<option value="' + xxStorageVendors[i] + '">'; }
            x += '</datalist>';
            x += '<datalist id=mstorageapplicationlist>';
            for (var i in xxStorageApplications) { x += '<option value="' + xxStorageApplications[i] + '">'; }
            x += '</datalist><datalist id=mstoragetypelist><option value="application/octet-stream"><option value="image/jpeg"><option value="text/html"><option value="text/plain"></datalist>';
            setDialogMode(11, "Storage Upload", 3, UploadToStorageEx, x, file);
            if (file) { SetStorageName(filename); }
        }

        // ###BEGIN###{Mode-NodeWebkit}
        /*
        var UploadAppToStorageFileList;
        function UploadAppToStorage() {
            if (xxdialogMode) return;
            require('fs').readdir('.', function read(err, data) {
                var filelist = [], filecount = 0;
                if (err == null) { for (var i in data) { if ((data[i].endsWith('.gz')) || (data[i].endsWith('.br'))) { filelist.push(data[i]); filecount++; } } }
                if (filecount > 0) {
                    var x = '';
                    x += "Select the web application to upload, this will replace the Intel&reg; AMT default web pages." + '<br><br><div style=height:26px><select id=mwebappsel style=float:right;width:240px>';
                    for (var i in filelist) { x += '<option value=' + i + '>' + filelist[i].substring(0, filelist[i].length - 3) + '</option>'; }
                    x += '</select><div>' + "Web Application" + '</div></div>';
                    setDialogMode(11, "Storage Application Upload", 3, UploadAppToStorageEx, x, filelist);
                }
            });
        }

        function UploadAppToStorageEx(b, filelist) {
            var file = filelist[Q('mwebappsel').value];
            require('fs').readFile(file, 'binary', function read(err, data) {
                if (err == null) { PushToStorage('index.htm', '<metadata><headers><h>Content-Encoding: ' + (file.endsWith('.br')?'br':'gzip') + '</h><h>Content-Type: text/html</h></headers></metadata>' + data); }
            });
        }
        */
        // ###END###{Mode-NodeWebkit}

        function UploadToStorageEx(button, tag) {
            if (!tag) {
                var x = Q('mstoragefile');
                if (x.files.length != 1) return;
                var reader = new FileReader();
                reader.onload = UploadToStorageEx2;
                reader.filename = x.files[0].name;
                reader.readAsBinaryString(x.files[0]);
            } else {
                var reader = new FileReader();
                reader.onload = UploadToStorageEx2;
                reader.filename = Q('mstoragefile').value;
                reader.readAsBinaryString(tag);
            }
        }

        function SetStorageName(filename) {
            if (!filename) {
                var x = Q('mstoragefile');
                if (x.files.length == 1) { filename = x.files[0].name; } else { filename = ''; }
            }
            filename = filename.split(' ').join('');
            var filenameSplit = filename.split('-');
            if (filenameSplit.length == 3 && filenameSplit[0].length < 12 && filenameSplit[1].length < 12) {
                Q('mstoragevendor').value = filenameSplit[0];
                Q('mstorageapplication').value = filenameSplit[1];
                filename = filenameSplit[2];
            }
            filename = filename.split('-').join('');
            if (filename.endsWith('.gz')) filename = filename.substring(0, filename.length - 3);
            if (filename.endsWith('.htm') || filename.endsWith('.html')) Q('mstoragetype').value = 'text/html';
            else if (filename.endsWith('.txt')) Q('mstoragetype').value = 'text/plain';
            if (filename.length > 11) filename = filename.substring(0, 11);
            Q('mstoragefilename').value = filename;
        }

        function UploadToStorageEx2(file) {
            var vaf, vendor = Q('mstoragevendor').value;
            var app = Q('mstorageapplication').value;
            var filename = Q('mstoragefilename').value;
            if (filename == '') filename = 'Filename';
            var mimetype = Q('mstoragetype').value;
            if (mimetype == '') mimetype = 'application/octet-stream';
            var link = Q('mstoragelink').value;
            if (vendor == '' && app == '' && (filename.toLowerCase() == 'logon.htm' || filename.toLowerCase() == 'index.htm')) {
                vaf = filename.toLowerCase();
            } else {
                if (vendor == '') vendor = 'Vendor';
                if (app == '') app = 'App';
                vaf = vendor + '/' + app + '/' + filename;
            }

            var data = '<metadata><headers>';
            var filename = file.target.filename;
            if (!filename) { filename = Q('mstoragefile').files[0].name; }
            if (filename.endsWith('.gz')) { data += '<h>Content-Encoding: gzip</h>'; }
            data += '<h>Content-Type: ' + mimetype + '</h></headers>'; // <h>X-UA-Compatible: IE=Edge</h>
            if (link != '') data += '<link>' + link + '</link>';
            data += '</metadata>' + file.target.result;

            PushToStorage(vaf, data);
        }

// ###END###{Storage}

// ###BEGIN###{Alarms}

        //
        // Alarm Panel
        //

        function _fmtdatetime(str) {
            return str.replace('T',' ').replace('Z','');
        }

        function _fmtinterval(str) {
            var cl = str.replace('T', '').substring(str.indexOf('P') + 1);
            cl = ' ' + cl.replace('D', " days ").replace('H', " hours ").replace('M'," minutes ");
            cl = cl.replace(" 1 days ", " 1 day ").replace(" 1 hours ", " 1 hour ").replace(" 1 minutes "," 1 minute ");
            return cl.substring(0, cl.length - 1);
        }

        function _fmttimepad(str) {
            str = '' + str;
            while (str.length < 2) { str = '0' + str; }
            return str;
        }

        var xxAlarms = null;

        function PullAlarms() {
            var x = TableStart2() + '<tr><td class=r1 style=padding-left:15px><br>' + "Manage wake alarms." + '<br><br>';
            amtstack.Enum('IPS_AlarmClockOccurrence', function(stack, name, response, status) {
                if (status == 200) {
                    QV('go23', true);
                    if (response.length > 0) {
                        xxAlarms = response;
                        for (var i = 0; i < response.length; i++) {
                            var waketime = new Date(response[i]['StartTime']['Datetime']);
                            var details = '<b>' + response[i]['ElementName'] + '</b>, ' + "wake on" + ' ' + waketime.toLocaleString().replace(', ', " at ");
                            if (response[i]['Interval'] != undefined) { details += " and each" + _fmtinterval(response[i]['Interval']['Interval']); }
                            if (response[i]['DeleteOnCompletion'] == true) { details += ", delete when done"; }
                            x += '<div class=itemBar onclick=showAlertDetails(' + i + ')><div style=float:right>';
                            if (xxAccountAdminName) x += ' ' + AddButton2("Edit...", 'showAddAlarm(" + i + ")');
                            x += '</div><div style=padding-top:3px;width:auto;float:left;overflow-x:hidden>' + details + '</div></div>';
                        }
                    } else {
                        xxAlarms = null;
                        x += '<div style=padding-left:15px><br><i>' + "No wake alarms registered." + '</i></div><br>';
                    }
                    var y = '<div>&nbsp;' + AddRefreshButton('PullAlarms()');
                    if (xxAccountAdminName) { y += AddButton2("Remove all alarms", 'RemoveAllAlarms()', xxAlarms ? '' : 'disabled') + AddButton("Add", 'showAddAlarm()'); }
                    x += '<br><td class=r1>' + TableEnd(y + '</div>');
                    QH('id_TableAlarm', x);
                }
            }, null, true);
        }

        function prepareAlarmOccurenceTemplate(id, nm, start, interval, del) {
            return '<d:AlarmTemplate xmlns:d=\"http://intel.com/wbem/wscim/1/amt-schema/1/AMT_AlarmClockService\" xmlns:s=\"http://intel.com/wbem/wscim/1/ips-schema/1/IPS_AlarmClockOccurrence\"><s:InstanceID>' + id + '</s:InstanceID><s:StartTime><p:Datetime xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/common\">' + start + '</p:Datetime></s:StartTime><s:Interval><p:Interval xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/common\">' + interval + '</p:Interval></s:Interval><s:DeleteOnCompletion>' + del + '</s:DeleteOnCompletion></d:AlarmTemplate>';
        }
        
        function RemoveAllAlarms(){
            setDialogMode(1, "Remove all wake alarms", 3, RemoveAllAlarmsEx, "Confirm removal of all wake alarms?");
        }

        function RemoveAllAlarmsEx() {
            var deleteCount = xxAlarms.length;
            for (var a in xxAlarms) { amtstack.Delete('IPS_AlarmClockOccurrence', xxAlarms[a], function(stack, name, response, status) { if (--deleteCount == 0) { PullAlarms(); }}); }
        }

        function showAddAlarm(alrm){
            if (xxdialogMode) return;
            QE('d25alarm_name', !alrm);
            if (alrm != undefined) {
                var alarm = xxAlarms[alrm], waketime = new Date(alarm['StartTime']['Datetime']);
                Q('d25alarm_name').value = alarm['ElementName'];
                Q('d25alarm_sdate').value = waketime.getFullYear() + '-' + _fmttimepad(waketime.getMonth() + 1) + '-' + _fmttimepad(waketime.getDate());
                Q('d25alarm_stime').value = waketime.getHours() + ':' + _fmttimepad(waketime.getMinutes()) + ':' + _fmttimepad(waketime.getSeconds());
                if (alarm['Interval']) {
                    var j = alarm['Interval']['Interval'].replace('P','').replace('T','').replace('D','D,').replace('H','H,').replace('M','M,').split(','), k = [0, 0, 0];
                    for (var i in j) {
                        var jl = j[i].length - 1;
                        if (j[i][jl] == 'D') { k[0] = parseInt(j[i].substring(0, jl)); }
                        if (j[i][jl] == 'H') { k[1] = parseInt(j[i].substring(0, jl)); }
                        if (j[i][jl] == 'M') { k[2] = parseInt(j[i].substring(0, jl)); }
                    }
                    Q('d25alarm_interval').value = k.join('-');
                } else {
                    Q('d25alarm_interval').value = '';
                }
                Q('d25alarm_doc').value = (alarm['DeleteOnCompletion'] == true)?1:0;
            } else {
                var currentTime = new Date();
                currentTime.setDate(new Date().getDate() + 1);
                Q('d25alarm_name').value = '';
                Q('d25alarm_sdate').value = currentTime.getFullYear() + '-' + _fmttimepad(currentTime.getMonth() + 1) + '-' + _fmttimepad(currentTime.getDate());
                Q('d25alarm_stime').value = currentTime.getHours() + ':' + _fmttimepad(currentTime.getMinutes()) + ':00';
                Q('d25alarm_interval').value = '';
                Q('d25alarm_doc').value = 0;
            }
            setDialogMode(25, "Add new alarm", (alrm != undefined)?7:3, showAddAlarmOk, '', alrm);
            alertDialogUpdate();
        }

        function alertDialogUpdate() {
            var il = Q('d25alarm_interval').value.split('-').length;
            var ok = (Q('d25alarm_name').value.length > 0) && (Q('d25alarm_sdate').value.split('-').length == 3) && (Q('d25alarm_stime').value.split(':').length == 3) && ((il == 1) || (il == 3));
            QE('idx_dlgOkButton', ok);
        }

        function showAddAlarmOk(button, alrm) {
            if (button == 2) { showAlertDetailsDelete(button, alrm); return; }
            var alarm_name = Q('d25alarm_name').value;
            var x1 = Q('d25alarm_sdate').value.split('-');
            var x2 = Q('d25alarm_stime').value.split(':');
            var t = new Date(x1[0], x1[1] - 1, x1[2], x2[0], x2[1], x2[2], 0); // Month is 0 = JAN, 11 = DEC
            var alarm_starttime = _fmttimepad(t.getUTCFullYear()) + '-' + _fmttimepad(t.getUTCMonth() + 1) + '-' + _fmttimepad(t.getUTCDate()) + 'T' + _fmttimepad(t.getUTCHours()) + ':' + _fmttimepad(t.getUTCMinutes()) + ':' + _fmttimepad(t.getUTCSeconds()) + 'Z';
            var x = Q('d25alarm_interval').value.split('-');
            if (x.length != 3) { x = [0, 0, 0]; }
            var alarm_interval = 'P' + x[0] + 'DT' + x[1] + 'H' + x[2] + 'M';
            var alarm_doc = (Q('d25alarm_doc').value == 1);
            var tpl = prepareAlarmOccurenceTemplate(alarm_name, alarm_name, alarm_starttime, alarm_interval, alarm_doc);
            if (alrm == undefined) {
                wsstack.ExecMethodXml(amtstack.CompleteName('AMT_AlarmClockService'), 'AddAlarm', tpl,
                    function (ws, resuri, response, status) {
                        if (status != 200) { messagebox("Add alarm", format("Failed to add alarm. Status: {0}.<br/>Verify the alarm is for a future time.", status)); return; }
                        if (response.Body['ReturnValue'] != 0) { messagebox("Add alarm", format("Failed to add alarm {0}.<br/>Verify the alarm is for a future time.", response.Body['ReturnValueStr'])); return; }
                        PullAlarms();
                    }
                );
            } else {
                var alarmx = Clone(xxAlarms[alrm]);
                alarmx['StartTime'] = '<p:Datetime xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/common\">' + alarm_starttime + '</p:Datetime>';
                alarmx['Interval'] = '<p:Interval xmlns:p=\"http://schemas.dmtf.org/wbem/wscim/1/common\">' + alarm_interval + '</p:Interval>';
                alarmx['DeleteOnCompletion'] = alarm_doc;
                amtstack.Put('IPS_AlarmClockOccurrence', alarmx, function (ws, resuri, response, status) {
                    if (status != 200) { messagebox("Edit alarm", format('Failed to change alarm. Status: {0}.<br/>Verify the alarm for at a future time.', status)); return; }
                    PullAlarms();
                }, null, null, { 'InstanceID' : alarmx['InstanceID']});
            }
        }

        function showAlertDetails(i) {
            if (xxdialogMode) return;
            var alarm = xxAlarms[i], waketime = new Date(alarm['StartTime']['Datetime']);
            var x = '<div style=text-align:left>' + addHtmlValue("Name", alarm['ElementName']) + addHtmlValue("Wake time", waketime.toLocaleString().replace(', ', ' at '));
            if (alarm['Interval'] != undefined) { x += addHtmlValue("Internal", _fmtinterval(alarm['Interval']['Interval'])); }
            x += addHtmlValue("After wake", (alarm['DeleteOnCompletion'] == true)?"Delete Alarm":"Keep Alarm") + '</div>';
            messagebox(format("Alarm {0}", alarm['ElementName']), x);
            setDialogMode(11, "Alarm " + alarm['ElementName'], 5, showAlertDetailsDelete, x, i);
        }

        function showAlertDetailsDelete(button, tag) {
            if (button == 2) { amtstack.Delete('IPS_AlarmClockOccurrence', xxAlarms[tag], function(stack, name, response, status) { PullAlarms(); }); }
        }

// ###END###{Alarms}

// ###BEGIN###{Scripting}

        //
        // Scripting
        //

        // Called by the "Run Script..." button. Display a dialog box to ask for the script file.
        function script_runScriptDlg() {
            if (xxdialogMode || scriptstate) return;
            setDialogMode(11, "Run Script", 3, script_runScriptDlgOk, '<br><input id=scriptopen type=file style=width:100% accept=.mescript>');
        }

        // Once the script file is selected, decode the script here.
        function script_runScriptDlgOk(r) {
            if (r != 1) return;
            var x = Q('scriptopen');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = script_onScriptRead;
            reader.readAsBinaryString(x.files[0]);
        }

        // Called once the script is decoded, get the script setup and start running it.
        function script_onScriptRead(file) {
            var x;
            try { x = JSON.parse(file.target.result); } catch (e) {}
            // ###BEGIN###{Scripting-Editor}
            if (currentView == 20) {
                // Load script into editor
                if (x['scriptText']) Q('scriptarea').value = x['scriptText'];
                if (x['mescript']) Q('compiledarea').value = rstr2hex(atob(x['mescript']));
                if (x['blocks']) { script_setBuildBlocks(x['blocks']); scriptViewButton(1); } else { script_setBuildBlocks(); scriptViewButton(0); }
                if (x['scriptBlocks']) { script_BlockScript = x['scriptBlocks']; } else { if (!script_BuildingBlocks) { script_BlockScript = []; } }

                // Update the scriptBlocks to the latest blocks. This is does because we may update an existing script to new blocks.
                for (var i in script_BlockScript) {
                    var block = script_BlockScript[i];
                    var xblock = script_BuildingBlocks[block['xname']];
                    if (xblock) {
                        var b = Clone(xblock); // Clone a new block, then set all the variables.
                        b['id'] = block['id'];
                        b['xname'] = block['xname'];
                        for (var j in b.vars) { if (block.vars[j]) { b.vars[j]['value'] = block.vars[j]['value']; } }
                        script_BlockScript[i] = b;
                    }
                }

                // Reset the script state
                fupdatescript();
                delete scriptstate;
                resetScriptButton();
                return;
            }
            // ###END###{Scripting-Editor}
            var startvars = { '_interactive':1 };
            // ###BEGIN###{Certificates}
            startvars['_certificates'] = 1;
            // ###END###{Certificates}
            // ###BEGIN###{!Mode-Firmware}
            startvars['_mode'] = 'Firmware';
            // ###END###{!Mode-Firmware}
            // ###BEGIN###{!Mode-MeshCentral2}
            startvars['_mode'] = 'MeshCentral2';
            // ###END###{!Mode-MeshCentral2}
            // ###BEGIN###{Mode-NodeWebkit}
            startvars['_mode'] = 'NodeWebkit';
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{Mode-LMS}
            startvars['_mode'] = 'LMS';
            // ###END###{Mode-LMS}
            // ###BEGIN###{Mode-WebSite}
            startvars['_mode'] = 'WebSite';
            // ###END###{Mode-WebSite}
            if (x && x['mescript']) scriptstate = script_setup(atob(x['mescript']), startvars);
            if (scriptstate) {
                scriptstate.wsstack = wsstack;
                scriptstate.amtstack = amtstack;
                scriptstate.onStep = script_updateScriptState;
                scriptstate.onConsole = script_console;
                scriptstate.start(100);
            } else {
                messagebox("Run Script", "Invalid script file.");
            }
        }

        // Called when the script changes state, displays the green status bar at the top of the web page.
        function script_updateScriptState() {
            if (scriptstate) {
                QV('id_scriptstatus', scriptstate.state > 0); center();
                if (scriptstate.state == 0) {
                    // ###BEGIN###{Mode-NodeWebkit}
                    if (urlvars['autoexit']) { // Exit if script finished running
                        require('nw.gui').Window.get().close();
                        //require('nw.gui').App.quit();
                        return;
                    }
                    // ###END###{Mode-NodeWebkit}
                    scriptstate = undefined;
                }
            }
        }

        // Called by a running script to update the console. The last message in the console is displayed in the top green bar.
        function script_console(msg) {
            if (msg.indexOf('INFO: ') == 0) { msg = msg.substring(6); }
            if (msg.indexOf('SUCCESS: ') == 0) { msg = msg.substring(9); }
            if (msg.indexOf('ERROR: ') == 0) { msg = msg.substring(7); }
            QH('id_scriptstatusstr', ', ' + msg);
        }

        // Called by the "Stop" button on the script status bar. Causes the script to stop.
        function script_Stop() {
            if (scriptstate) {
                if (scriptstate.dialog == true) { setDialogMode(0); }
                scriptstate.stop();
                scriptstate.state = 0;
                script_updateScriptState();
            }
        }

// ###END###{Scripting}

// ###BEGIN###{Scripting-Editor}
        
        var script_BuildingBlocks; // List of block that can be used to build a script. This is shown on the list side.
        var script_StartingBuildingBlocks; // List of block that can be used to build a script when you get started.
        var script_BlockScript = []; // List of blocks that are part of the current script.
        var script_BlockScriptSelectedId = null; // The identifier of the currently selected block.
        var script_BuilderView = 0; // 0 = Editor View, 1 = Builder View
        var editscriptstate; // This is the instance of the script runner used by the editor. This is different from the runner used by the web page.

        // ###BEGIN###{!Mode-Firmware}
        function scriptLoadStartingBlocks() {
            // ###BEGIN###{!Mode-NodeWebkit}
            var request = new XMLHttpRequest();
            request.onload = function() {
                if (request.status >= 200 && request.status < 400) {
                    // Success
                    var x;
                    try { x = JSON.parse(request.responseText); } catch (e) {}
                    if ((x) && (x['blocks'])) { script_StartingBuildingBlocks = x['blocks']; script_setBuildBlocks(script_StartingBuildingBlocks); }
                }
            };
            request.onerror = function() { console.log('Failed to get script blocks'); };
            request.open('GET', 'scriptblocks.txt', true);
            request.send();
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var content;
            require('fs').readFile('scriptblocks.txt', 'utf8', function read(err, data) {
                if (err == null) {
                    var x;
                    try { x = JSON.parse(data); } catch (e) {}
                    if (x['blocks']) { script_StartingBuildingBlocks = x['blocks']; script_setBuildBlocks(script_StartingBuildingBlocks); }
                }
            });
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{!Mode-Firmware}

        // Called by the "View Editor" or "View Builder" button to toggle between the view modes.
        // If there is no construction blocks, display the script editor only.
        function scriptViewButton(x) {
            script_BuilderView = x;
            QV('scripteditor', x == 0);
            QV('scriptbuilder', x == 1);
            QV('viewEditorButton', script_BuildingBlocks && (x == 1));
            QV('viewBuilderButton', script_BuildingBlocks && (x == 0));
        }

        // Display the list of construction script block on the left side.
        function script_setBuildBlocks(blocks) {
            script_BuildingBlocks = blocks;
            var x = '';
            if (blocks) {
                for (var i in blocks) {
                    if (i.charCodeAt(0) != 95) {
                        x += '<div id=sblock_' + i + ' style=cursor:pointer;background-color:#ccc;width:auto;padding:5px;margin:2px ondblclick=script_faddblock("' + i + '") draggable=true ondragstart=script_fondragstart(event,this) ondragend=script_fondragend(event,this) title="' + blocks[i]['desc'] + '"';
                        // ###BEGIN###{ContextMenus}
                        var cmenus = [];
                        cmenus.push("Add " + '#script_faddblock("' + i + '")');
                        cmenus.push("Edit..." + '#script_feditblock("' + i + '")');
                        x += ' cm=\"' + cmenus.join('|') + '\"';
                        // ###END###{ContextMenus}
                        x += '>' + blocks[i]['name'] + '</div>';
                    }
                }
            }
            QH('blocks', x);
            script_fonfilterchanged();
            scriptViewButton(script_BuildingBlocks?1:0);
        }

        // Add a new block to the end of the block script. This is called when you right click on a block and hit "Add" in the context menu.
        function script_faddblock(h) {
            var b = Clone(script_BuildingBlocks[h]); // To add a new block to the script, clone the block, assign it a random id and set the xname to the name of the block.
            b['id'] = Math.random();
            b['xname'] = h;
            script_BlockScript.push(b); // Now that a block is created, add it at the end of the script and set it as the selected block.
            script_BlockScriptSelectedId = script_BlockScript.length - 1;
            fupdatescript(); // Re-display the list of script blocks. The selected block will also be highlighted.
        }

        // Edit a script block
        function script_feditblock(h) {
            if (xxdialogMode) return;
            setDialogMode(11, format("Edit {0}", script_BuildingBlocks[h]['name']), 3, script_feditblockEx, 'Edit this block? This operation will reset the block editor and load the block code into the code editor.', h);
        }

        // Called when the script block edit dialog is closed.
        function script_feditblockEx(button, h) {
            script_newScriptDlgOk();
            scriptViewButton(0);
            var x = '', b = script_BuildingBlocks[h];
            x += '##!BLOCK!##\r\n#id=' + h + '\r\n#name=' + b['name'] + '\r\n#desc=' + b['desc'] + '\r\n##!BLOCK!##\r\n';
            for (var i in b['vars']) {
                var v = b['vars'][i];
                x += '##!VAR!##\r\n#id=' + i + '\r\n#name=' + v['name'] + '\r\n#desc=' + v['desc'] + '\r\n#type=' + v['type'] + '\r\n';
                if (v['maxlength']) { x += '#maxlength=' + v['maxlength'] + '\r\n'; }
                if (v['values']) { for (var j in v['values']) { x += '#values-' + j +'=' + v['values'][j] + '\r\n'; } }
                x += '#value=' + v['value'] + '\r\n##SWAP %%%' + i + '%%% ' + v['value'] + '\r\n';
            }
            x += '##!VAR!##\r\n##SWAP %%%~%%% 0\r\n\r\n##!BLOCK!##\r\n' + b['code'] + '\r\n##!BLOCK!##\r\n';
            Q('scriptarea').value = x;
        }

        function script_fConvertScriptToJsonBlock(script) {
            var result = {}, scriptparts = script.split('##!BLOCK!##\n'), scriptlines = scriptparts[1].split('\n');

            // Parse information part
            for (var i in scriptlines) {
                var s = scriptlines[i].split('=');
                if (s.length == 2) { result[s[0].substring(1)] = s[1]; }
            }

            // Parse variables part
            result['vars'] = {};
            scriptvariables = scriptparts[2].split('##!VAR!##\n');
            for (var i in scriptvariables) {
                scriptlines = scriptvariables[i].split('\n');
                var v = {}, values = {}, valueslen = 0;
                for (var j in scriptlines) {
                    var s = scriptlines[j].split('=');
                    if ((s.length == 2) && (s[1])) {
                        if ((s[0]) && (s[0].length > 0)) {
                            if (s[0].substring(0, 8) == '#values-') {
                                values[s[0].substring(8)] = s[1];
                                valueslen++;
                            } else {
                                v[s[0].substring(1)] = s[1];
                            }
                        }
                    }
                }
                if (v.id) {
                    if (valueslen > 0) { v['values'] = values; }
                    var id = v.id;
                    delete v.id;
                    result['vars'][id] = v;
                }
            }

            // Parse code part
            result['code'] = scriptparts[3];

            // Package the result
            var id = result.id;
            delete result.id;
            var r = {};
            r[id] = result;
            return JSON.stringify(r, null, '  ');
        }

        /*
        // If the delete key is pressed, delete the block
        function script_fonkeypress(e) {
            if (xxdialogMode) return;
            if (e.key == 'Delete' && script_BlockScriptSelectedId != null) {
                //delete script_BlockScript[script_BlockScriptSelectedId];
                script_BlockScript.splice(script_BlockScriptSelectedId, 1);
                script_BlockScriptSelectedId = null;
                fupdatescript();
            }
        }
        */

        // Filer the list of blocks on the left side list.
        function script_fonfilterchanged() {
            var filter = Q('blockfilter').value.toLowerCase();
            for (var i in script_BuildingBlocks) {
                // Script blocks that start with "_" are hidden blocks and should never be shown.
                if (i.charCodeAt(0) != 95) { QV('sblock_' + i, (script_BuildingBlocks[i]['name'].toLowerCase().indexOf(filter) >= 0 || script_BuildingBlocks[i]['desc'].toLowerCase().indexOf(filter) >= 0)); }
            }
        }

        // Called when you click on a block. If you double click, on a block, do like pressing on the "Edit..." button.
        var script_fonclickDblClickDetectIndex = null;
        var script_fonclickDblClickDetectTime = null;
        function script_fonclick(e, t) {
            // ###BEGIN###{ContextMenus}
            hideContextMenu(); // Any click on this area must close the context menu
            // ###END###{ContextMenus}
            if (xxdialogMode) return;
            script_BlockScriptSelectedId = null;
            if (t) { t = fgetParentWithId(t); if (t.id.startsWith('xblock_')) { script_BlockScriptSelectedId = t.id.substring(7); } } // Figure out what block was clicked on
            fupdatescript(); // This will show the currently selected block in a different color.
            haltEvent(e);

            // Figure out if this is a double click. We need two clicks on the same object within 250ms.
            if (script_fonclickDblClickDetectIndex == script_BlockScriptSelectedId && (new Date().getTime() - script_fonclickDblClickDetectTime) < 250) { return script_foneditclick(script_BlockScriptSelectedId); }
            script_fonclickDblClickDetectIndex = script_BlockScriptSelectedId;
            script_fonclickDblClickDetectTime = new Date().getTime();
        }

        // Script block drag & drop functions, allow the user to create and move script blocks.
        function script_fondragstart(e, t) { if (xxdialogMode) return; t = fgetParentWithId(t); t.style.opacity = '0.4'; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('scriptbuilder/block', t.id); }
        function script_fondragend(e, t)   { if (xxdialogMode) return; t = fgetParentWithId(t); t.style.opacity = '1.0'; }
        function script_fondragenter(e, t) { if (xxdialogMode) return; fgetParentWithId(t).style['border-top'] = 'solid 2px black'; }
        function script_fondragleave(e, t) { if (xxdialogMode) return; e = e.originalEvent || e; var currentElement = document.elementFromPoint(e.pageX, e.pageY); if (!t.contains(currentElement)) { fgetParentWithId(t).style['border-top'] = 'none'; } }

        // Called when you drop a block on the block script area. This code will add or move a block into it's new place.
        function script_fondrop(e, t) {
            if (xxdialogMode) return;
            t = fgetParentWithId(t);
            var b, x = e.dataTransfer.getData('scriptbuilder/block'), dp = parseInt(t.id.substring(7));
            if (x == '') { documentFileSelectHandler(e); return; }
            if (x.startsWith("sblock_")) {
                // Create a new script block
                b = Clone(script_BuildingBlocks[x.substring(7)]);
                b['id'] = Math.random();
                b['xname'] = x.substring(7);
            } else {
                // Pull an existing script block from the list
                var i = parseInt(x.substring(7));
                b = script_BlockScript[i];
                script_BlockScript.splice(i, 1);
                if (dp > i) dp--;
            }
            if (t.id == 'scriptblocks') {
                // Put the block at the end of the list
                if (b) script_BlockScript.push(b);
                script_BlockScriptSelectedId = script_BlockScript.length - 1;
            } else {
                // Insert the block within the list, above the drop point
                script_BlockScript.splice(dp, 0, b);
                script_BlockScriptSelectedId = dp;
            }
            fupdatescript();
            haltEvent(e);
        }

        // Called when you hit "Edit..." on a block, displays a dialog box with all block attributes.
        function script_foneditclick(h) {
            if (xxdialogMode) return;
            var block = script_BlockScript[h];
            script_BlockScriptSelectedId = h;
            fupdatescript();

            if (block != null) {
                var b = block['vars'] ? 7 : 5;
                var c = block['desc'] + '<br><br>';
                if (block['vars']) {
                    // For each variable in a block, add the proper input control for this variable and set the control to the current value.
                    for (var i in block['vars']) {
                        var d = block['vars'][i]['value'];
                        var attributes = '';
                        // Block values can be on type 1:Text,2:Number,3:DropDownList,4:password,5:MultiSelect
                        if (block['vars'][i]['maxlength']) attributes += (' maxlength=' + block['vars'][i]['maxlength']);
                        if (block['vars'][i]['type'] == 2) { attributes += ' onkeypress=\'return numbersOnly(event)\'' }
                        if (block['vars'][i]['type'] == 1 || block['vars'][i]['type'] == 2) { d = '<input title="' + block['vars'][i]['desc'] + '" id=scriptXvalue_' + i + ' value="' + block['vars'][i]['value'] + '" ' + attributes + ' style=width:100%></input>'; }
                        if (block['vars'][i]['type'] == 3) {
                            d = '<select title=\'' + block['vars'][i]['desc'] + '\' id=scriptXvalue_' + i + ' style=width:100%;padding:0;margin:0>';
                            for (var j in block['vars'][i]['values']) { d += '<option value=' + j + (j == block['vars'][i]['value'] ? ' selected' : '') + '>' + block['vars'][i]['values'][j] + '</option>'; }
                            d += '</select>';
                        }
                        if (block['vars'][i]['type'] == 4) { d = '<input type=password autocomplete=off title="' + block['vars'][i]['desc'] + '" id=scriptXvalue_' + i + ' value="' + block['vars'][i]['value'] + '" ' + attributes + ' style=width:100%></input>'; }
                        if (block['vars'][i]['type'] == 5) { d = ''; }
                        if (block['vars'][i]['type'] == 6) { d = '<input type=file title="' + block['vars'][i]['desc'] + '" id=scriptXvalue_' + i + ' ' + attributes + ' style=width:100%></input>'; }
                        c += '<table style=width:100% title="' + block['vars'][i]['desc'] + '"><td style=width:120px>' + block['vars'][i]['name'] + '<td><b>' + d + '</b></table>';
                        if (block['vars'][i]['type'] == 5) {
                            var x = '';
                            c += '<ul id=scriptXvalue_' + i + ' style="list-style-type:none;height:100px;overflow:auto;width:100%;border:1px solid #000;background-color:white;overflow-x:hidden;margin:0;padding:0">';
                            for (var y in block['vars'][i]['values']) {
                                var xc = '';
                                if (block['vars'][i]['value'].indexOf(y) >= 0) xc = ' checked';
                                c += '<li><label><input type=checkbox id=scriptXvaluex_' + i + '-' + y + '' + xc + '>' + block['vars'][i]['values'][y] + '</label></li>';
                            }
                            c += '</ul>';
                        }
                    }
                }
            }

            // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 11 only)
            setDialogMode(11, block.name, b, script_foneditclickEx, c, h);
        }

        // Called when the script block edit dialog is closed.
        function script_foneditclickEx(button, tag) {
            if (xxdialogMode) return;
            if (button == 2) {
                // Delete this block
                script_BlockScript.splice(tag, 1);
                if (script_BlockScriptSelectedId == tag) { script_BlockScriptSelectedId = null; }
            } else {
                // Change this block with new arguments
                var block = script_BlockScript[tag];
                if (block['vars']) {
                    for (var i in block['vars']) {
                        if (block['vars'][i]['type'] == 5) {
                            block['vars'][i]['value'] = [];
                            for (var y in block['vars'][i]['values']) { if (Q('scriptXvaluex_' + i + '-' + y).checked) block['vars'][i]['value'].push(y); }
                        } else if (block['vars'][i]['type'] == 6) {
                            var x = Q('scriptXvalue_' + i);
                            if (x.files.length == 1) {
                                var reader = new FileReader();
                                reader.onload = function(file) { block['vars'][i]['value'] = btoa(file.target.result); fupdatescript(); };
                                reader.readAsBinaryString(x.files[0]);
                            }
                        } else {
                            block['vars'][i]['value'] = Q('scriptXvalue_' + i).value;
                        }
                    }
                }
            }
            fupdatescript();
        }

        // Starting with a child element, go up one parent at a time until we find an element with an ID.
        function fgetParentWithId(x) { while (!x.id) { x = x.parentElement; } return x; }

        // Displays the list of script blocks to the HTML page. Each block is displayed with it's name, attributes and an edit button.
        function fupdatescript() {
            var x = '';
            for (var i in script_BlockScript) {
                x += '<div id=xblock_' + i + ' style=cursor:pointer;min-height:24px;background-color:#' + ((script_BlockScriptSelectedId == i) ? 'aaa' : 'ccc') + ';width:auto;padding:5px;margin:2px draggable=true onclick=script_fonclick(event,this) ondragenter=script_fondragenter(event,this) ondragleave=script_fondragleave(event,this) ondragstart=script_fondragstart(event,this) ondragend=script_fondragend(event,this) ondrop=script_fondrop(event,this) title="' + script_BlockScript[i]['desc'] + '"';
                // ###BEGIN###{ContextMenus}
                var cmenus = [];
                cmenus.push("Edit..." + '#script_foneditclick('+i+')');
                cmenus.push("Delete" + '#script_foneditclickEx(2,'+i+')');
                x += ' cm=\'' + cmenus.join('|') + '\'';
                // ###END###{ContextMenus}
                x += '><input style=float:right type=button value=Edit... onclick=script_foneditclick(' + i + ')><div style=font-size:16px><b>' + script_BlockScript[i].name + '</b>';
                if (script_BlockScript[i]['vars']) {
                    var r = 0;
                    x += '<table class="scriptBlockVar us" cellpadding=0 cellspacing=0 style=width:100%;border-radius:5px;margin-top:8px>';
                    for (var j in script_BlockScript[i]['vars']) {
                        var v = script_BlockScript[i]['vars'][j]['value'];
                        if (script_BlockScript[i]['vars'][j]['type'] == 4 && script_BlockScript[i]['vars'][j]['value'].length > 0) v = '*****';
                        if (script_BlockScript[i]['vars'][j]['type'] == 3) v = script_BlockScript[i]['vars'][j]['values'][script_BlockScript[i]['vars'][j]['value']];
                        if (script_BlockScript[i]['vars'][j]['type'] == 6) {
                            if (script_BlockScript[i]['vars'][j]['value']) { v = "Binary file, " + script_BlockScript[i]['vars'][j]['value'].length + " bytes"; } else { v = "Not set"; }
                        }
                        x += '<tr title="' + script_BlockScript[i]['vars'][j]['desc'] + '"><td width=200px style="' + (r > 0 ? 'border-top:1px solid #a810a8' : '') + '"><p>' + script_BlockScript[i]['vars'][j]['name'] + '<td style="' + (r > 0 ? 'border-top:1px solid #a810a8' : '') + '">' + v;
                        r++;
                    }
                    x += '<tr><td style=height:3px></table>';
                }
                x += '</div></div>';
            }
            if (x == '') { x = '<div style=\"padding:15px;color:gray\">' + "Start your script by drag & dropping blocks from the left side into this scripting box." + '<div>'; }
            QH('scriptblocks', x + '<div style=height:80px></div>');
            for (var i in script_BlockScript) { QS('xblock_' + i).borderLeft = (script_CurrentHighlightBlock == i) ? '3px solid black' : ''; }
            script_blocksToScript();
        }

        // Convert the list of blocks into a script that can be compiled
        function script_blocksToScript() {
            var script = '';
            if (script_BuildingBlocks) {
                if (script_BuildingBlocks['_start']) { script += '##### Starting Block #####\r\n' + script_BuildingBlocks['_start']['code'] + '\r\n\r\n'; }
                for (var i in script_BlockScript) {
                    var code = script_BlockScript[i]['code'];
                    code = code.split('%%%~%%%').join(i);
                    for (var j in script_BlockScript[i]['vars']) { code = code.split('%%%' + j + '%%%').join(script_BlockScript[i]['vars'][j]['value']); }
                    script += '##### Block: ' + script_BlockScript[i]['name'] + ' #####\r\nHighlightBlock __t ' + i + '\r\n' + code + '\r\n\r\n';
                }
                if (script_BuildingBlocks['_end']) { script += '##### Ending Block #####\r\n' + script_BuildingBlocks['_end']['code'] + '\r\nHighlightBlock\r\n'; }
            }
            Q('scriptarea').value = script;
        }

        // Highlight a script block. This is useful to know what block the script is currently running
        var script_CurrentHighlightBlock;
        function script_HighlightBlock(runner, x) {
            if (runner == editscriptstate) { // Only highlight blocks if the scrpt editor is running the script. If running a script on the page, don't highlight blocks in the editor.
                script_CurrentHighlightBlock = x;
                for (var i in script_BlockScript) { QS('xblock_' + i).borderLeft = (script_CurrentHighlightBlock == i) ? '3px solid black' : ''; }
            }
        }

        // Called by the "New..." button to reset the script editor to the start
        function script_newScriptDlg() {
            if (xxdialogMode) return;
            setDialogMode(11, "New Script", 3, script_newScriptDlgOk, '<br>' + "Reset & clear the script editor?");
        }

        // Clear the script editor
        function script_newScriptDlgOk() {
            script_setBuildBlocks(script_StartingBuildingBlocks);
            script_BlockScript = [];
            script_BlockScriptSelectedId = null;
            delete editscriptstate;
            scriptViewButton(script_BuildingBlocks?1:0);
            QH('variables', '');
            Q('scriptarea').value = '';
            resetScriptButton();
        }

        // Compile and reset a script to the starting position
        function resetScriptButton() {
            // Compile the script
            breakScriptButton();
            Q('compiledarea').value = rstr2hex(script_compile(Q('scriptarea').value, function(m) { messagebox("Script Compile Error", m); }));
            delete editscriptstate;

            // Reset the script environment
            Q('console').value = '';
            QH('variables', '');
            QH('EditScriptStatus', "Stopped");
            if (script_BuilderView == 1) { fupdatescript(); }
            if (Q('compiledarea').value.length == 0) return;

            // Create a new script runtime object
            var startvars = { '_interactive':1 };
            // ###BEGIN###{Certificates}
            startvars['_certificates'] = 1;
            // ###END###{Certificates}
            // ###BEGIN###{!Mode-Firmware}
            startvars['_mode'] = 'Firmware';
            // ###END###{!Mode-Firmware}
            // ###BEGIN###{!Mode-MeshCentral2}
            startvars['_mode'] = 'MeshCentral2';
            // ###END###{!Mode-MeshCentral2}
            // ###BEGIN###{Mode-NodeWebkit}
            startvars['_mode'] = 'NodeWebkit';
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{Mode-LMS}
            startvars['_mode'] = 'LMS';
            // ###END###{Mode-LMS}
            // ###BEGIN###{Mode-WebSite}
            startvars['_mode'] = 'WebSite';
            // ###END###{Mode-WebSite}
            editscriptstate = script_setup(hex2rstr(Q('compiledarea').value), startvars);
            editscriptstate.wsstack = wsstack;
            editscriptstate.amtstack = amtstack;
            editscriptstate.onStep = editscript_updateScriptState;
            editscriptstate.onConsole = editscript_console;
            editscript_updateScriptState(editscriptstate);
        }

        // Start running the script
        function runScriptButton() {
            if (editscriptstate == null) resetScriptButton();
            if (editscriptstate == null) return;
            editscriptstate.start(100);
        }

        // Stop/Pause the script
        function breakScriptButton() {
            if (editscriptstate == null) return;
            editscriptstate.stop();
        }

        // Run one step of the script
        function stepScriptButton() {
            if (editscriptstate == null) resetScriptButton();
            if (editscriptstate == null) return;
            breakScriptButton();
            editscriptstate.step();
        }

        // Display a new line into the script console
        function editscript_console(msg) {
            Q('console').value += (msg + '\n');
        }

        // Update the script state information and displayed variables
        var script_states = ["Stopped", "Running", "Paused"];
        function editscript_updateScriptState(runstate) {
            // Update variables
            var r = '';
            if (runstate && runstate != null) {
                var vs = [];
                for (var i in runstate.variables) { if (!i.startsWith('__')) vs.push(i); }
                vs.sort();
                //for (var i in vs) { r += vs[i] + ' = ' + script_toString(runstate.variables[vs[i]]) + "\n"; }
                for (var i in vs) {
                    if (typeof runstate.variables[vs[i]] == 'object') {
                        r += '<b>' + vs[i] + '</b> = ' + ObjectToStringEx(runstate.variables[vs[i]], 2) + '<br>';
                    } else {
                        r += '<b>' + vs[i] + '</b> = ' + EscapeHtml(script_toString(runstate.variables[vs[i]])) + '<br>';
                    }
                }
            }
            QH('variables', r);

            // Update state
            r = "Stopped, No Script";
            if (runstate && runstate != null) { r = script_states[runstate.state]; if (runstate.state > 0) r += ', ' + runstate.ip + ' : ' + script_decompile(runstate.script, runstate.ip); }
            if (r.length > 50) { r = r.substring(0, 50) + "..."; }
            QH('EditScriptStatus', r);
        }

        // Return a string from any input, if the input is an object, stringify it.
        function script_toString(x) { if (typeof x == 'object') return JSON.stringify(x); return x; }

        // ###BEGIN###{FileSaver}
        // Save a script to disk, start by showing a dialog box to prompt to the filename.
        function script_saveScript(e) {
            if (xxdialogMode || scriptstate) return;
            if (e && (e.shiftKey == true)) {
                // Save as script block
                setDialogMode(11, "Script Block", 1, null, '<br><textarea id=scriptSaveScriptJsonBlock style=width:100%;height:200px;resize:vertical />');
                QH('scriptSaveScriptJsonBlock', script_fConvertScriptToJsonBlock(Q('scriptarea').value));
            } else {
                // Save as .mescript file
                // ###BEGIN###{!Mode-NodeWebkit}
                setDialogMode(11, "Save Script", 3, script_saveScriptOk, '<br><input id=scriptsavename style=width:100% value=test.mescript >');
                // ###END###{!Mode-NodeWebkit}
                // ###BEGIN###{Mode-NodeWebkit}
                var chooser = document.createElement('input');
                chooser.setAttribute('type', "file")
                chooser.setAttribute('nwsaveas', "script.mescript");
                chooser.addEventListener('change', function() {
                    require('fs').writeFile(this.value, JSON.stringify({
                        'scriptText': Q('scriptarea').value,
                        'mescript': btoa(script_compile(Q('scriptarea').value)),
                        'blocks': script_StartingBuildingBlocks,
                        'scriptBlocks': script_BlockScript
                    }, null, '  ').replace(/\n/g, '\r\n'), function () { });
                }, false);
                chooser.click();
                // ###END###{Mode-NodeWebkit}
            }
        }

        // Once the filename is selected, save the file.
        function script_saveScriptOk() {
            if (xxdialogMode) return;
            var x = JSON.stringify({
                'scriptText': Q('scriptarea').value,
                'mescript': btoa(script_compile(Q('scriptarea').value)),
                'blocks': script_StartingBuildingBlocks,
                'scriptBlocks': script_BlockScript
            }, null, '  ');
            saveAs(data2blob(x), Q('scriptsavename').value);
        }
        // ###END###{FileSaver}

// ###END###{Scripting-Editor}

// ###BEGIN###{CertificateManager}

        //
        // Certificate Manager
        //

        /*
        function issueCertButtonOk() {
            var certopen = getInputElement('certopen');
            var files = xxDragDropCertFiles;
            if (certopen) files = certopen.files;
            if (files && files.length == 1) {
                // Issue a certificate using this file
                var reader = new FileReader();
                reader.onload = issueCertButtonOk2;
                reader.readAsBinaryString(files[0]);
            } else {
                // Issue a certificate using a dummy CA
                issueCertButtonOk3(null);
            }
        }
        */

        var certificateStore = [];
        var currentCertificate = null;

        function cert_updateCertificateList() {
            var x = '', certcount = 0;
            if (currentCertificate == null && certificateStore.length > 0) { currentCertificate = certificateStore[0]; }
            certificateStore.sort(function (a, b) { var aa = a.cert.subject.getField('CN').value; var bb = b.cert.subject.getField('CN').value; if (aa > bb) { return 1; } if (aa < bb) { return -1; } return 0; });
            for (var y in certificateStore) {
                try {
                    var certificate = certificateStore[y], name = certificate.cert.subject.getField('CN').value, extra = [];
                    if (certificate['tlsauth']) { extra.push('<span title="' + "This certificate will be used to authenticate this console to Intel AMT." + '">' + "TLS Authentication" + '</span>'); }
                    if (certificate['trusted'] == true) { extra.push('<span title="' + "We trust certificates signed by this certificate." + '">' + "Trusted" + '</span>'); }
                    if (certificate['privateKey']) { extra.push('<span title="' + "We have the private key for this certificate." + '">' + "Private Key" + '</span>'); }
                    x += '<div style=margin:4px;cursor:pointer>';
                    x += '<img src=images-commander/cert' + ((certificate['privateKey'])?'2':'1') + '.png style=vertical-align:text-top;float:left;background-color:white;height:28px height=32 width=32 />';
                    x += '<div id=LCR-' + certificate['h'] + ' class=g1 style=float:left;height:28px>&nbsp;</div><div id=RCR-' + certificate['h'] + ' class=g2 style=float:right;height:28px>&nbsp;</div><div style=height:28px ';
                    // ###BEGIN###{ContextMenus}
                    var cmenus = [];
                    cmenus.push("View..." + '#cert_view(' + certificate['h'] +'")');
                    if (certificate['privateKey']) { cmenus.push("Issue new cert..." + '#cert_issueNew(' + certificate['h'] + ')'); }
                    cmenus.push("Export as .cer..." + '#cert_saveCertCer(' + certificate['h'] + ')');
                    if (certificate['privateKey']) { cmenus.push("Export as .p12..." + '#cert_saveCertP12(' + certificate['h'] + ')'); }
                    x += ' cm=\'' + cmenus.join('|') + '\'';
                    // ###END###{ContextMenus}
                    x += ' onclick=\'cert_select(event, ' + certificate['h'] + ')\' id=CR-' + certificate['h'] + ' ondblclick=cert_view(' + certificate['h'] + ')>';
                    //x += '<input id=SC-' + certificate['h'] + ' type=checkbox style=float:left;margin-top:8px onclick=cert_onCertificateChecked()' + (certificate.checked?' checked':'') + ' />';
                    x += '<div style=float:right><span style=font-size:14px>' + extra.join(', ') + '</span>&nbsp;<input type=button value="' + "View..." + '" onclick=cert_view(' + certificate['h'] + ')>&nbsp;</div><div style=padding-top:2px>&nbsp;';
                    // ###BEGIN###{Look-BrandedCommander}
                    //x += '<img src=images-BrandedCommander/ComputerIcon.png style=vertical-align:text-top />&nbsp;';
                    // ###END###{Look-BrandedCommander}
                    //x += '<img src=certificate.png style=vertical-align:text-top height=28 width=24 />';
                    x += '<b style=font-size:16px>' + EscapeHtml(name) + '</b></div></div></div>';
                    certcount++;
                } catch (e) { delete certificateStore[y]; }
            }
            QV('id_certStartScreen', certcount == 0);
            QH('id_certManagerMainArea', x);
            cert_select();
        }

        function cert_view(h) {
            if (xxdialogMode) return;
            var x = '', certificate = getCertificate(h), cert = certificate.cert, commonName = cert.subject.getField('CN').value;
            var fingerprint = '', fingerprint2 = forge.md.sha1.create().update(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()).digest().toHex().toUpperCase();
            for (i = 0; i < fingerprint2.length; i++) { if ((i != 0) && (i % 2 == 0)) { fingerprint += ':'; } fingerprint += fingerprint2.substring(i, i + 1); }
            x += '<img src=images-commander/cert' + ((certificate['privateKey']) ? '2' : '1') + '.png style=vertical-align:text-top;float:right;height:28px height=32 width=32 />';
            x += '<input id=certTrustedCheck type=checkbox>' + "This is a trusted certificate" + '<br>';
            var extKeyUsage = null;
            for (var i in certificate.cert.extensions) { if (certificate.cert.extensions[i].id == '2.5.29.37') { extKeyUsage = certificate.cert.extensions[i]; } }
            if ((certificate['privateKey']) && (extKeyUsage != null) && (extKeyUsage['2.16.840.1.113741.1.2.1'] == true)) { x += '<div><input id=certMutualAuth type=checkbox>' + "Use for TLS console authentication" + '<br></div>'; }
            x += '<br>';
            // ###BEGIN###{FileSaver}
            var y = atob(certificate['certbin']).length + " bytes, " + '<a style=cursor:pointer;color:blue onclick=cert_saveCertCer(' + h + ',1)>' + NoBreak("Save .cer") + '</a>';
            if (certificate['privateKey']) { y += ', <a style=cursor:pointer;color:blue onclick=cert_saveCertP12(' + h + ')>' + NoBreak("Save .p12") + '</a>'; }
            y += ', <a style=cursor:pointer;color:blue onclick=cert_saveCertCer(' + h + ',2)>' + NoBreak("Save .pem") + '</a>';
            x += addHtmlValueNoTitle("Certificate", y);
            // ###END###{FileSaver}
            // ###BEGIN###{!FileSaver}
            //x += addHtmlValueNoTitle("Certificate", c.X509Certificate.length + " bytes");
            // ###END###{!FileSaver}
            // Decode certificate usages
            y = [];
            if (extKeyUsage != null) {
                if (extKeyUsage.clientAuth == true) { y.push(NoBreak("TLS Client")); }
                if (extKeyUsage.codeSigning == true) { y.push(NoBreak("Code Signing")); }
                if (extKeyUsage.emailProtection == true) { y.push("EMail"); }
                if (extKeyUsage.serverAuth == true) { y.push(NoBreak("TLS Server")); }
                if (extKeyUsage['2.16.840.1.113741.1.2.1'] == true) { y.push(NoBreak("Intel&reg; AMT Console")); }
                if (extKeyUsage['2.16.840.1.113741.1.2.2'] == true) { y.push(NoBreak("Intel&reg; AMT Agent")); }
                if (extKeyUsage['2.16.840.1.113741.1.2.3'] == true) { y.push(NoBreak("Intel&reg; AMT Activation")); }
                if (extKeyUsage.timeStamping == true) { y.push(NoBreak("Time Stamping")); }
                if (y.length > 0) { x += addHtmlValueNoTitle("Certificate Usage", y.join(', ') + '.') + '<br clear=all />'; }
            }
            x += '<br><div style=\"border-bottom:1px solid gray\"><i>' + "Certificate Subject" + '</i></div><br>';
            for (var i in xxCertSubjectNames) { var a = cert.subject.getField(i); if (a) { x += addHtmlValue(xxCertSubjectNames[i], EscapeHtml(a.value)); } }
            x += addHtmlValueNoTitle("Fingerprint", fingerprint.substring(0,29) + '<br />' + fingerprint.substring(30));
            x += '<br><div style="border-bottom:1px solid gray"><i>' + "Issuer Certificate" + '</i></div><br>';
            for (var i in xxCertSubjectNames) { var a = cert.issuer.getField(i); if (a) { x += addHtmlValue(xxCertSubjectNames[i], EscapeHtml(a.value)); } }
            setDialogMode(11, "Certificate - " + EscapeHtml(commonName), 5, cert_viewex, x, certificate);
            Q('certTrustedCheck').checked = (certificate['trusted'] == true);
            if (certificate['privateKey'] && Q('certMutualAuth')) { Q('certMutualAuth').checked = (certificate['tlsauth'] == true); }
        }

        function cert_saveCertCer(h,type) {
            var certificate = getCertificate(h), cert = certificate.cert, commonName = cert.subject.getField('CN').value;
            // ###BEGIN###{!Mode-NodeWebkit}
            //saveAs(data2blob(xxCertificates[h].X509Certificate), xxCertificates[h].XSubject['CN'] + '.cer');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            if (type == 1) { // .cer format
                chooser.setAttribute('nwsaveas', commonName + '.cer');
                chooser.addEventListener('change', function () { require('fs').writeFile(this.value, certificate['certbin'], 'base64', function () { }); }, false);
            } else if (type == 2) { // .pem format
                chooser.setAttribute('nwsaveas', commonName + '.pem');
                chooser.addEventListener('change', function () {
                    var ptr = 0, xcert = '';
                    // Write the public certificate
                    while (ptr < certificate['certbin'].length) { xcert += certificate['certbin'].substring(ptr, ptr + Math.min(certificate['certbin'].length - ptr, 64)) + '\r\n'; ptr += 64; }
                    xcert = '-----BEGIN CERTIFICATE-----\r\n' + xcert + '-----END CERTIFICATE-----\r\n';
                    if (certificate['privateKeyBin']) { xcert += '\r\n' + certificate['privateKeyBin']; } // Write the private key
                    require('fs').writeFile(this.value, xcert, function () { });
                }, false);
            }
            chooser.click();
            setDialogMode(0);
            // ###END###{Mode-NodeWebkit}
        }

        function cert_saveCertP12(h) {
            // Prompt to the PKCS12 password
            var x = "Enter a certificate private key password." + '<br/><br/><div style=height:26px><input id=idx_filepass1 type=password onkeyup=cert_saveCertP12Update() style=float:right;width:200px><div>' + "Password" + '</div></div><div style=height:26px><input id=idx_filepass2 type=password onkeyup=cert_saveCertP12Update() style=float:right;width:200px><div>' + "Password" + '</div></div>';
            setDialogMode(11, "Certificate Password", 3, cert_saveCertP12b, x, h);
            cert_saveCertP12Update();
        }

        function cert_saveCertP12Update() {
            QE('idx_dlgOkButton', (Q('idx_filepass1').value == Q('idx_filepass2').value) && (Q('idx_filepass1').value.length > 0));
        }

        function cert_saveCertP12b(b, h) {
            var certificate = getCertificate(h), cert = certificate.cert, commonName = cert.subject.getField('CN').value, pass = Q('idx_filepass1').value;
            // ###BEGIN###{!Mode-NodeWebkit}
            //saveAs(data2blob(xxCertificates[h].X509Certificate), xxCertificates[h].XSubject['CN'] + '.cer');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('nwsaveas', commonName + '.p12');
            chooser.addEventListener('change', function() {
                require('fs').writeFile(this.value, forge.util.encode64(forge.asn1.toDer(forge.pkcs12.toPkcs12Asn1(certificate['privateKey'], certificate['cert'], pass)).getBytes()), 'base64', function () { });
            }, false);
            chooser.click();
            setDialogMode(0);
            // ###END###{Mode-NodeWebkit}
        }

        function cert_viewex(b, certificate) {
            if (b == 2) {
                cert_removeCertificateEx(certificate['h']);
            } else {
                var update = 0;
                if (certificate['trusted'] != Q('certTrustedCheck').checked) { certificate['trusted'] = Q('certTrustedCheck').checked; update = 1; }
                if ((certificate['privateKey']) && Q('certMutualAuth') && (certificate['tlsauth'] != Q('certMutualAuth').checked)) {
                    for (var y in certificateStore) { certificateStore[y]['tlsauth'] = false; }
                    certificate['tlsauth'] = Q('certMutualAuth').checked;
                    update = 1;
                }
                if (update == 1) { cert_updateCertificateList(); cert_saveCertificates(); }
            }
        }

        function cert_removeCertificateEx(h) {
            cert_deleteCertificatesEx(2, [ getCertificate(h) ]);
        }

        function cert_select(e, h) {
            if (h) { currentCertificate = getCertificate(h); /*updateComputerDetails();*/ }
            for (var y in certificateStore) {
                var certificate = certificateStore[y];
                var sel = (currentCertificate != null && certificate['h'] == currentCertificate['h']);
                QS('CR-' + certificate['h'])['background-color'] = sel ? '#a0a0a0' : '#c9c9c9';
                Q('LCR-' + certificate['h']).classList.remove('g1');
                Q('LCR-' + certificate['h']).classList.remove('g1s');
                Q('RCR-' + certificate['h']).classList.remove('g2');
                Q('RCR-' + certificate['h']).classList.remove('g2s');
                Q('LCR-' + certificate['h']).classList.add(sel ? 'g1s' : 'g1');
                Q('RCR-' + certificate['h']).classList.add(sel ? 'g2s' : 'g2');
            }
            QE('IssueCertButton', (currentCertificate != null) && (currentCertificate['privateKey']));
        }

        function getCertificate(h) { for (var i in certificateStore) { if (certificateStore[i]['h'] == h) return certificateStore[i]; } return null; }
        function getCertificateWithKeyCount(h) { for (var i in certificateStore) { var c = 0; if (certificateStore[i]['privateKey']) { c++; } } return c; }
        function getTlsAuthCertificate() { for (var i in certificateStore) { if (certificateStore[i]['tlsauth'] == true) return certificateStore[i]; } return null; }

        function cert_onCertificateChecked() {
            for (var y in certificateStore) { certificateStore[y].checked = Q('SC-' + certificateStore[y]['h']).checked; }
        }

        function cert_deleteCertificates() {
            if (xxdialogMode) return;
            // Figure out how many certificates are selected.
            var clist = [];
            for (var y in certificateStore) { if (certificateStore[y].checked == true) { clist.push(certificateStore[y]); } }
            if (clist.length == 0) { clist.push(currentCertificate); }
            if (clist.length == 1) {
                setDialogMode(11, "Delete Certificates", 3, cert_deleteCertificatesEx, '<br>' + "Delete 1 certificate?", clist);
            } else {
                setDialogMode(11, "Delete Certificates", 3, cert_deleteCertificatesEx, '<br>' + format("Delete {0} certificates?", clist.length), clist);
            }
        }

        function cert_deleteCertificatesEx(button, clist) {
            for (var i in clist) {
                var handleToDelete = clist[i]['h'];
                if ((currentCertificate != null) && (currentCertificate['h'] == handleToDelete)) { currentCertificate = null; }
                for (x = 0; x < certificateStore.length; x++) { if (certificateStore[x]['h'] == handleToDelete) { certificateStore.splice(x, 1); } }
            }
            cert_saveCertificates();
            cert_updateCertificateList();
            //updateComputerDetails();
        }

        function cert_loadCertificates() {
            // ###BEGIN###{Mode-NodeWebkit}
            var ctext = null;
            try { ctext = localStorage.getItem('certificates'); } catch (ex) { }
            if (ctext) {
                try { computerlist = JSON.parse(ctext); } catch (e) {
                    if (ctext.length > 512) { // Add trivial security, not intended to be real security. This just avoids storing data in plain text, but it's almost the same.
                        var crypto = require('crypto'), k = ctext.substring(0, 512), crypted = ctext.substring(512), decipher = crypto.createDecipher('aes-256-ctr', k), dec = decipher.update(crypted, 'hex', 'utf8');
                        dec += decipher.final('utf8');
                        var certificateStore2 = JSON.parse(dec);
                        if (Array.isArray(certificateStore2) == false) { certificateStore2 = []; }
                        for (var i in certificateStore2) {
                            try {
                                certificateStore2[i].checked = false;
                                if (certificateStore2[i]['certbin']) { certificateStore2[i]['cert'] = forge.pki.certificateFromAsn1(forge.asn1.fromDer(atob(certificateStore2[i]['certbin']))); }
                                if (certificateStore2[i]['privateKeyBin']) { certificateStore2[i]['privateKey'] = forge.pki.privateKeyFromPem(certificateStore2[i]['privateKeyBin']); }
                            } catch (e) { delete certificateStore2[i]; }
                        }
                        certificateStore = [];
                        for (var i in certificateStore2) { if (typeof certificateStore2[i] == 'object') certificateStore.push(certificateStore2[i]); }
                    }
                }
            }
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            //var ctext = null;
            //try { ctext = localStorage.getItem('computers'); } catch (ex) { }
            //if (ctext) { computerlist = JSON.parse(ctext); }
            // ###END###{!Mode-NodeWebkit}
            cert_updateCertificateList();
        }

        function cert_saveCertificates() {
            // ###BEGIN###{Mode-NodeWebkit}
            const crypto = require('crypto'); 
            crypto.randomBytes(256, function(err, buf) {
                if (err) throw err; // Add trivial security, not intended to be real security. This just avoids storing data in plain text, but it's almost the same.
                var k = buf.toString('hex'), cipher = crypto.createCipher('aes-256-ctr', k), crypted = cipher.update(JSON.stringify(certificateStore), 'utf8', 'hex');
                crypted += cipher.final('hex');
                try { localStorage.setItem('certificates', k + crypted); } catch (ex) { }
            });
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            //try { localStorage.setItem('computers', JSON.stringify(computerlist)); } catch (ex) { }
            // ###END###{!Mode-NodeWebkit}
        }

        function cert_createNew() {
            if (xxdialogMode) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certcn style=float:right;width:230px><div style=padding-top:4px>' + "Common Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certo style=float:right;width:230px><div style=padding-top:4px>' + "Organization" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certst style=float:right;width:230px><div style=padding-top:4px>' + "State/Province" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certc style=float:right;width:230px><div style=padding-top:4px>' + "Country" + '</div></div>';
            setDialogMode(11, "Create Root Certificate", 3, cert_createNewEx, x);
            cert_createNew_Update();
        }

        function cert_createNew_Update() {
            x = (getInputElement('certcn').value != '' && getInputElement('certo').value != '' && getInputElement('certst').value != '' && getInputElement('certc').value != '');
            QE('idx_dlgOkButton', x);
        }

        // --- Extended Key Usage OID's ---
        // 1.3.6.1.5.5.7.3.1            = TLS Server certificate
        // 1.3.6.1.5.5.7.3.2            = TLS Client certificate
        // 2.16.840.1.113741.1.2.1      = Intel AMT Remote Console
        // 2.16.840.1.113741.1.2.2      = Intel AMT Local Console
        // 2.16.840.1.113741.1.2.3      = Intel AMT Client Setup Certificate (Zero-Touch)

        function cert_createNewEx(b, rootCert) {
            // Generate a keypair and create an X.509v3 certificate
            var keys = forge.pki.rsa.generateKeyPair(2048);
            var cert = forge.pki.createCertificate();
            cert.publicKey = keys.publicKey;
            cert.serialNumber = '' + Math.floor((Math.random() * 100000) + 1);
            cert.validity.notBefore = new Date(2018, 0, 1);
            //cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don't reject this cert.
            cert.validity.notAfter = new Date(2049, 11, 31);
            //cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20);
            var attrs = [
                { name: 'commonName', value: Q('certcn').value },
                { name: 'countryName', value: Q('certc').value },
                { shortName: 'ST', value: Q('certst').value },
                { name: 'organizationName', value: Q('certo').value }
            ];
            cert.setSubject(attrs);

            if (rootCert) {
                // Use root attributes
                cert.setIssuer(rootCert['cert'].subject.attributes);
            } else {
                // Use our own attributes
                cert.setIssuer(attrs);
            }

            if (rootCert == undefined) {
                // Create a root certificate
                cert.setExtensions([{
                    name: 'basicConstraints',
                    cA: true
                }, {
                    name: 'nsCertType',
                    sslCA: true,
                    emailCA: true,
                    objCA: true
                }, {
                    name: 'subjectKeyIdentifier'
                }]);
            } else {
                // Figure out the extended key usages
                var extKeyUsage = { name: 'extKeyUsage' }
                if (Q('d11_cu1').checked) { extKeyUsage['2.16.840.1.113741.1.2.1'] = true; extKeyUsage.clientAuth = true; }
                if (Q('d11_cu2').checked) { extKeyUsage['2.16.840.1.113741.1.2.2'] = true; extKeyUsage.clientAuth = true; }
                if (Q('d11_cu3').checked) { extKeyUsage['2.16.840.1.113741.1.2.3'] = true; extKeyUsage.clientAuth = true; }
                if (Q('d11_cu4').checked) { extKeyUsage.serverAuth = true; }
                if (Q('d11_cu5').checked) { extKeyUsage.clientAuth = true; }
                if (Q('d11_cu6').checked) { extKeyUsage.emailProtection = true; }
                if (Q('d11_cu7').checked) { extKeyUsage.codeSigning = true; }
                if (Q('d11_cu8').checked) { extKeyUsage.timeStamping = true; }

                // Create a leaf certificate
                cert.setExtensions([{
                    name: 'basicConstraints'
                }, {
                    name: 'keyUsage',
                    keyCertSign: true,
                    digitalSignature: true,
                    nonRepudiation: true,
                    keyEncipherment: true,
                    dataEncipherment: true
                }, extKeyUsage, {
                    name: 'nsCertType',
                    client: Q('d11_cu5').checked,
                    server: Q('d11_cu4').checked,
                    email: Q('d11_cu6').checked,
                    objsign: Q('d11_cu7').checked,
                }, {
                    name: 'subjectKeyIdentifier'
                } ]);
            }

            // Self-sign certificate
            if (rootCert) {
                cert.sign(rootCert['privateKey'], forge.md.sha256.create());
            } else {
                cert.sign(keys.privateKey, forge.md.sha256.create());
            }

            // Save the certificate in the store
            certificateStore.push({ 'h': Math.random(), 'cert': cert, 'certbin': btoa(hex2rstr(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).toHex())), 'privateKey': keys.privateKey, 'privateKeyBin': forge.pki.privateKeyToPem(keys.privateKey), 'checked': false });
            cert_saveCertificates();
            cert_updateCertificateList();
        }

        function cert_issueNew() {
            if (xxdialogMode) return;
            var x = '';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certcn style=float:right;width:230px><div style=padding-top:4px>' + "Common Name" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certo style=float:right;width:230px><div style=padding-top:4px>' + "Organization" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certst style=float:right;width:230px><div style=padding-top:4px>' + "State/Province" + '</div></div>';
            x += '<div style=height:26px;margin-top:4px><input onkeyup=cert_createNew_Update() id=certc style=float:right;width:230px><div style=padding-top:4px>' + "Country" + '</div></div>';
            x += '<div>Certificate Usages</div><ul style="list-style-type:none;height:100px;overflow:auto;width:100%;border: 1px solid #000;background-color:white;overflow-x:hidden;margin:0;padding:0">';
            x += '<li><label><input type=checkbox id=d11_cu1>' + "Intel&reg; AMT Console" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu2>' + "Intel&reg; AMT Agent" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu3>' + "Intel&reg; AMT Activation" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu4>' + "TLS Server (HTTPS)" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu5>' + "TLS Client (HTTPS)" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu6>' + "Email Protection" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu7>' + "Code Signing" + '</label></li>';
            x += '<li><label><input type=checkbox id=d11_cu8>' + "Time Stamp" + '</label></li>';
            x += '</ul>';
            setDialogMode(11, format("Issue Certificate signed by {0}", currentCertificate.cert.subject.getField('CN').value), 3, cert_createNewEx, x, currentCertificate);
            cert_issueNew_Update();
        }

        function cert_issueNew_Update() {
            x = (getInputElement('certcn').value != '' && getInputElement('certo').value != '' && getInputElement('certst').value != '' && getInputElement('certc').value != '');
            QE('idx_dlgOkButton', x);
        }

        function cert_importCert() {
            if (xxdialogMode) return;
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = Q('certOpenFile');
            if (chooser.getAttribute('eventset') != 1) {
                chooser.setAttribute('eventset', '1');
                chooser.addEventListener('change', cert_importCertOk, false);
            }
            chooser.value = null;
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }

        function cert_importCertOk2(e) {
            haltEvent(e);
            if (e.dataTransfer.files.length == 1) {
                var reader = new FileReader();
                if (e.dataTransfer.files[0].name.toLowerCase().endsWith('.p12') || e.dataTransfer.files[0].name.toLowerCase().endsWith('.pfx')) {
                    reader.onload = cert_importCertOkP12;
                } else {
                    reader.onload = cert_importCertOkCER;
                }
                reader.readAsBinaryString(e.dataTransfer.files[0]);
            }
        }

        function cert_importCertOk() {
            var x = Q('certOpenFile');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            if (x.files[0].name.toLowerCase().endsWith('.p12') || x.files[0].name.toLowerCase().endsWith('.pfx')) { reader.onload = cert_importCertOkP12; } else { reader.onload = cert_importCertOkCER; }
            reader.readAsBinaryString(x.files[0]);
        }

        function cert_importCertOkP12(file) {
            // Prompt to the PKCS12 password
            var x = "The selected certificate file requires a password." + '<br/><br/><div style=height:26px><input id=idx_filepass type=password style=float:right;width:200px><div>' + "Password" + '</div></div>';
            setDialogMode(11, "Certificate Password", 3, cert_importCertOkP12b, x, file);
        }

        function cert_importCertOkP12b(button, file) {
            // Try to decode the PKCS12 file
            var p12;
            try { p12 = forge.pkcs12.pkcs12FromAsn1(forge.asn1.fromDer(file.target.result), Q('idx_filepass').value); } catch (e) { setDialogMode(11, "Certificate File", 1, function() {}, "Invalid certificate password or unable to decode file."); return; }
            var bags1 = p12.getBags({bagType: forge.pki.oids.certBag});
            var cert = bags1[forge.pki.oids.certBag][0].cert;
            var bags2 = p12.getBags({bagType: '1.2.840.113549.1.12.10.1.2'})
            var key = bags2['1.2.840.113549.1.12.10.1.2'][0].key;
            certificateStore.push({ 'h': Math.random(), 'cert': cert, 'certbin': btoa(hex2rstr(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).toHex())), 'privateKey': key, 'privateKeyBin': forge.pki.privateKeyToPem(key), 'checked': false });
            cert_saveCertificates();
            cert_updateCertificateList();
        }

        function cert_importCertOkCER(file) {
            var cert, str = file.target.result;
            var pemcert = cert_getMiddleString(str, '-----BEGIN CERTIFICATE-----', '-----END CERTIFICATE-----');
            var pemkey = cert_getMiddleString(str, '-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----');
            if (pemkey == null) { pemkey = cert_getMiddleString(str, '-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----'); }
            if (pemcert != null) {
                // Try to decode the .PEM file
                try { cert = forge.pki.certificateFromPem(pemcert); } catch (e) { setDialogMode(11, "Certificate File", 1, function () { }, "Unable to decode PEM file."); return; }
                if (pemkey == null) {
                    // Public key only
                    certificateStore.push({ 'h': Math.random(), 'cert': cert, 'certbin': btoa(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()), 'checked': false });
                } else {
                    // Public and private key
                    var privatekey;
                    try { privatekey = forge.pki.privateKeyFromPem(pemkey); } catch (e) { setDialogMode(11, "Certificate File", 1, function () { }, "Unable to decode PEM private key."); return; }
                    certificateStore.push({ 'h': Math.random(), 'cert': cert, 'certbin': btoa(forge.asn1.toDer(forge.pki.certificateToAsn1(cert)).getBytes()), 'privateKey': privatekey, 'privateKeyBin': forge.pki.privateKeyToPem(privatekey), 'checked': false });
                }
            } else {
                // Try to decode the .CER file, public key only
                try { cert = forge.pki.certificateFromAsn1(forge.asn1.fromDer(str)); } catch (e) { setDialogMode(11, "Certificate File", 1, function () { }, "Unable to decode certificate file."); return; }
                certificateStore.push({ 'h': Math.random(), 'cert': cert, 'certbin': btoa(file.target.result), 'checked': false });
            }
            cert_saveCertificates();
            cert_updateCertificateList();
        }

        function cert_getMiddleString(str, start, end) { var a = str.indexOf(start), b = str.indexOf(end); if ((a == -1) || (b == -1) || (b < a)) return null; return str.substring(a, b + end.length); }

// ###END###{CertificateManager}
        
// ###BEGIN###{USBSetup}

        //
        // USB SETUP.BIN
        //

        function usb_newSetupBin() {
            if (xxdialogMode) return;
            idx_d14version.value = 4;
            idx_d14consume.value = 1;
            setDialogMode(14, "Create new Setup.bin file", 3, usb_newSetupBinOk);
        }

        function usb_newSetupBinOk(r) {
            if (r == 1) { setupbin = AmtSetupBinCreate(idx_d14version.value, idx_d14consume.value); } // OK Button
            usb_displaySetupBin();
        }

        function usb_openSetupBin() {
            if (xxdialogMode) return;
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('accept', '.bin')
            chooser.addEventListener('change', function() {
                setupbin = AmtSetupBinDecode(require('fs').readFileSync(this.value, 'binary'));
                if (!setupbin) { messagebox("Open File", "Invalid or corrupt setup.bin file. Unable to open."); } else { usb_displaySetupBin(); }
            }, false);
            chooser.value = null;
            chooser.click();
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{!Mode-NodeWebkit}
            setDialogMode(15, "Open Setup.bin file", 3, usb_openSetupBinOk);
            // ###END###{!Mode-NodeWebkit}
        }

        function usb_openSetupBinOk() {
            var x = Q('d15setupbinfile');
            if (x.files.length != 1) return;
            var reader = new FileReader();
            reader.onload = usb_onSetupBinRead;
            reader.readAsBinaryString(x.files[0]);
        }

        // ###BEGIN###{FileSaver}
        function usb_saveSetupBin() {
            if (xxdialogMode || !setupbin) return;
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(AmtSetupBinEncode(setupbin)), 'setup.bin');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('nwsaveas', 'setup.bin');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, AmtSetupBinEncode(setupbin), 'binary', function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

        function usb_onSetupBinRead(file) {
            setupbin = AmtSetupBinDecode(file.target.result);
            if (!setupbin) { messagebox("Open File", "Invalid or corrupt setup.bin file. Unable to open."); } else { usb_displaySetupBin(); }
        }

        function usb_displaySetupBin() {
            QV('id_StartupScreen', !setupbin);
            // ###BEGIN###{FileSaver}
            QV('id_saveSetupBin', setupbin);
            // ###END###{FileSaver}
            if (!setupbin) { return QH('id_SetupBinArea', ''); }
            
            // Update record count
            var consumed = 0;
            for (var i in setupbin.records) { if ((setupbin.records[i].flags & 1) == 0) { consumed++; } }
            setupbin.dataRecordsConsumed = consumed;

            // Main Header            
            var x = '<table onclick=usb_editheader(event) class="log1 us" cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px;cursor:pointer><tr><td><p><td>';
            x += '<tr><td class=r2 style=padding-left:15px>';
            x += '<div style=float:right;margin-right:12px onclick=usb_addRecordSetupBin()><a><u title=\'' + "Add a new record" + '\'>' + "Add Record" + '</u></a></div>';
            x += '<div><strong>' + format("Intel&reg; AMT Setup.bin file version {0}.{1}", setupbin.majorVersion, + setupbin.minorVersion) + '</strong>.</div>';
            x += (((setupbin.flags & 1) == 0) ? 'Records will be consumed.' : 'Records will not be consumed.');
            x += '<br>' + format("Records: {0}, Consumed: {1}", setupbin.records.length, setupbin.dataRecordsConsumed)+ '<br>';
            x += '<tr style=height:4px></table>';

            // Display each record
            for (var i in setupbin.records) {
                var rec = setupbin.records[i];
                x += '<div style=height:4px></div><table class="log1 us" cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td><tr><td class=r2 style=padding-left:15px;cursor:pointer>';
                x += '<div style=float:right;margin-right:12px onclick="usb_addvariable(event,' + i + ')"><a><u title="' + "Add a new variable" + '">' + "Add Variable" + '</u></a></div>';
                x += '<div onclick=\'usb_editrecord(event, ' + i + ')\'>' + "Record #" + '<strong>' + (+i + 1) + '</strong>. ' + "This record is: " + '<strong>' + ((rec.flags & 1) ? "Valid" : "Consumed") + ((rec.flags & 2) ? ", Scrambled" : '') + '</strong></div>';

                // Display each variable
                for (var j in rec.variables) {
                    var v = rec.variables[j], val = v.value;
                    if (AmtSetupBinVarIds[v.moduleid][v.varid][2] && AmtSetupBinVarIds[v.moduleid][v.varid][2][val]) { val = AmtSetupBinVarIds[v.moduleid][v.varid][2][val]; }
                    if (v.moduleid == 2 && v.varid == 8) {
                        var hashtype = val.charCodeAt(0);
                        if (hashtype >= 0 && hashtype <= 3) {
                            var hashsize = [20, 32, 48][hashtype - 1];
                            var hash = rstr2hex(val.substring(1, hashsize + 1));
                            var hashnamesize = val.charCodeAt(1 + hashsize);
                            var hashname = val.substring(2 + hashsize, 2 + hashsize + hashnamesize)
                            val = ['SHA1', 'SHA256', 'SHA384'][hashtype - 1] + ', ' + hashname + ', ' + hash;
                        }
                    }
                    if (v.moduleid == 2 && v.varid == 17) {
                        val = val.charCodeAt(3) + '.' + val.charCodeAt(2) + '.' + val.charCodeAt(1) + '.' + val.charCodeAt(0);
                    }
                    x += '<div style=margin-right:12px><table onclick=\'usb_editvariable(event,' + i + ',' + j + ')\' class=\'itemBar us\' cellpadding=0 cellspacing=0 style=width:100%;border-radius:4px;margin-top:2px;margin-bottom:2px;padding:0><tr><td><p style=float:right;margin-right:8px><b>' + val + '</b><p>' + v['desc'] + '<tr style=height:4px></table></div>';
                }

                x += '<tr style=height:4px></table>';
            }

            QH('id_SetupBinArea', x);
        }

        function usb_addRecordSetupBin() {
            if (xxdialogMode) return;
            d13valid.checked = 1;
            d13scramble.checked = 0;
            QV('d13ScrambledRecordSpan', setupbin.majorVersion > 3);
            setDialogMode(13, "New Record #", 3, usb_addRecordSetupBinOk);
        }

        function usb_addRecordSetupBinOk() {
            var r = {};
            r.typeIdentifier = 1;
            r.flags = (d13valid.checked ? 1 : 0) + (d13scramble.checked ? 2 : 0);
            r.chunkCount = 0;
            r.headerByteCount = 0;
            r.number = 0;
            r.variables = [];
            setupbin.records.push(r);
            usb_displaySetupBin();
        }

        function usb_editheader(e) {
            if (xxdialogMode) return;
            haltEvent(e);
            idx_d14version.value = setupbin.majorVersion;
            idx_d14consume.value = (setupbin.flags & 1);
            setDialogMode(14, "Edit Header", 7, usb_editheaderok);
        }

        function usb_editheaderok(r) {
            if (r == 2) {
                delete setupbin;
            } else {
                setupbin.majorVersion = idx_d14version.value;
                setupbin.flags = idx_d14consume.value;
            }
            usb_displaySetupBin();
        }

        function usb_editrecord(e, i) {
            if (xxdialogMode) return;
            selectedRecord = i;
            selectedVariable = -1;
            haltEvent(e);
            d13valid.checked = (setupbin.records[selectedRecord].flags & 1);
            d13scramble.checked = (setupbin.records[selectedRecord].flags & 2);
            QV('d13ScrambledRecordSpan', setupbin.majorVersion > 3);
            setDialogMode(13, format("Edit Record #{0}", (i + 1)), 7, usb_editrecordok);
        }

        function usb_editrecordok(r) {
            if (r == 1) { setupbin.records[selectedRecord].flags = (d13valid.checked ? 1 : 0) + (d13scramble.checked ? 2 : 0); } // Edit Record
            if (r == 2) { setupbin.records.splice(selectedRecord, 1); } // Delete Record
            usb_displaySetupBin();
        }

        function usb_editvariable(e, i, j) {
            if (xxdialogMode) return;
            selectedRecord = i;
            selectedVariable = j;
            var modid = setupbin.records[i].variables[j].moduleid;
            var varid = setupbin.records[i].variables[j].varid;
            d16type.value = modid + '-' + varid;
            d16type.disabled = true;
            usb_ond16typechange();
            QV('d16genericvalue', false);
            QV('d16customvalue', false);
            if (modid == 2 && varid == 8) {
                var x = '<div style=height:26px><select id=idx_d16valc1 style=float:right;width:260px onchange=usb_ond16checkhash()><option value=1>' + "SHA1" + '</option>';
                if (setupbin.majorVersion >= 3) { x += '<option value=2>SHA256</option><option value=3>' + "SHA384" + '</option>'; }
                x += '</select><div>' + "Hash Type" + '</div></div>';
                x += '<div style=height:26px><input id=idx_d16valc2 style=float:right;width:260px onkeyup=usb_ond16checkhash()><div>' + "Hash (HEX)" + '</div></div>';
                x += '<div style=height:26px><input id=idx_d16valc3 style=float:right;width:260px onkeyup=usb_ond16checkhash() maxlength=31><div>' + "Hash Name" + '</div></div>';
                QH('d16customvalue', x);
                QV('d16customvalue', true);
                var val = setupbin.records[i].variables[j].value;
                var hashtype = val.charCodeAt(0);
                if (hashtype >= 0 && hashtype <= 3) {
                    var hashsize = [20, 32, 48][hashtype - 1];
                    var hash = rstr2hex(val.substring(1, hashsize + 1));
                    var hashnamesize = val.charCodeAt(1 + hashsize);
                    var hashname = val.substring(2 + hashsize, 2 + hashsize + hashnamesize)
                    val = ["SHA1", "SHA256", "SHA384"][hashtype - 1] + ', ' + hashname + ', ' + hash;
                    Q('idx_d16valc1').value = hashtype;
                    Q('idx_d16valc2').value = hash;
                    Q('idx_d16valc3').value = hashname;
                }
                usb_ond16checkhash();
            } else if (modid == 2 && varid == 17) {  // Provisioning server address
                QV('d16genericvalue', true);
                var ip = setupbin.records[i].variables[j].value;
                idx_d16value1.value = idx_d16value2.value = ip.charCodeAt(3) + '.' + ip.charCodeAt(2) + '.' + ip.charCodeAt(1) + '.' + ip.charCodeAt(0);
            } else {
                QV('d16genericvalue', true);
                idx_d16value1.value = idx_d16value2.value = setupbin.records[i].variables[j].value;
            }
            haltEvent(e);
            setDialogMode(16, format("Edit Record #{0}, Variable #{1}", (i + 1), (j + 1)), 7, usb_editvariableok);
        }

        function usb_editvariableok(r) {
            if (r == 1) { // OK
                var ids = d16type.value.split('-');
                var modid = +ids[0];
                var varid = +ids[1];
                var value = '';
                var vardescription = AmtSetupBinVarIds[modid][varid];
                if ((modid == 2) && (varid == 8)) {
                    value = String.fromCharCode(Q('idx_d16valc1').value) + hex2rstr(Q('idx_d16valc2').value) + String.fromCharCode(Q('idx_d16valc3').value.length) + Q('idx_d16valc3').value;
                } else {
                    if (vardescription[2]) { value = idx_d16value1.value; } else { value = idx_d16value2.value; }
                }
                if ((modid == 2) && (varid == 17)) {  // Provisioning server address
                    var ipSplit = value.split('.');
                    if (ipSplit.length != 4) return;
                    value = String.fromCharCode(parseInt(ipSplit[3]), parseInt(ipSplit[2]), parseInt(ipSplit[1]), parseInt(ipSplit[0]));
                }
                setupbin.records[selectedRecord].variables[selectedVariable].value = value;
            }
            if (r == 2) { setupbin.records[selectedRecord].variables.splice(selectedVariable, 1); } // Delete
            usb_displaySetupBin();
        }

        function usb_addvariable(e, i) {
            if (xxdialogMode) return;
            selectedRecord = i;
            d16type.value = '1-1';
            d16type.disabled = false;
            idx_d16value1.value = idx_d16value2.value = '';
            usb_ond16typechange();
            haltEvent(e);
            setDialogMode(16, format("Add Variable to Record #{0}", (i + 1)), 3, usb_addvariableok);
        }

        function usb_addvariableok() {
            var ids = d16type.value.split('-');
            var modid = +ids[0];
            var varid = +ids[1];
            var value = '';
            var vardescription = AmtSetupBinVarIds[modid][varid];
            if ((modid == 2) && (varid == 8)) {
                value = String.fromCharCode(Q('idx_d16valc1').value) + hex2rstr(Q('idx_d16valc2').value) + String.fromCharCode(Q('idx_d16valc3').value.length) + Q('idx_d16valc3').value;
            } else {
                if (vardescription[2]) { value = idx_d16value1.value; } else { value = idx_d16value2.value; }
            }
            if ((modid == 2) && (varid == 17)) { // Provisioning server address
                var ipSplit = value.split('.');
                if (ipSplit.length != 4) return;
                value = String.fromCharCode(parseInt(ipSplit[3]), parseInt(ipSplit[2]), parseInt(ipSplit[1]), parseInt(ipSplit[0]));
            }

            // Create a new variable
            var v = {};
            v.moduleid = modid;
            v.varid = varid;
            v.length = -1;
            v.type = AmtSetupBinVarIds[modid][varid][0];
            v.desc = AmtSetupBinVarIds[modid][varid][1];
            v.value = value;
            setupbin.records[selectedRecord].variables.push(v);

            setupbin.records[selectedRecord].variables.sort(AmtSetupBinVariableCompare); // Sort the variables
            usb_displaySetupBin();
        }

        function usb_ond16typechange() {
            var ids = d16type.value.split('-');
            var modid = +ids[0];
            var varid = +ids[1];
            var vardescription = AmtSetupBinVarIds[modid][varid];
            QV('d16genericvalue', false);
            QV('d16customvalue', false);
            if (modid == 2 && varid == 8) {
                var x = '<div style=height:26px><select id=idx_d16valc1 style=float:right;width:260px onchange=usb_ond16checkhash()><option value=1>' + "SHA1" + '</option>';
                if (setupbin.majorVersion >= 3) { x += ('<option value=2>' + "SHA256" + '</option><option value=3>' + "SHA384" + '</option>'); }
                x += '</select><div>' + "Hash Type" + '</div></div>';
                x += '<div style=height:26px><input id=idx_d16valc2 style=float:right;width:260px onkeyup=usb_ond16checkhash()><div>' + "Hash (HEX)" + '</div></div>';
                x += '<div style=height:26px><input id=idx_d16valc3 style=float:right;width:260px onkeyup=usb_ond16checkhash() maxlength=31><div>' + "Hash Name" + '</div></div>';
                QV('d16customvalue', true);
                QH('d16customvalue', x);
                usb_ond16checkhash();
            } else {
                QV('d16genericvalue', true);
                if (vardescription[2]) {
                    QV('idx_d16value1', true);
                    QV('idx_d16value2', false);
                    var options = '';
                    for (var i in vardescription[2]) { options += '<option value="' + i + '">' + vardescription[2][i] }
                    QH('idx_d16value1', options);
                } else {
                    QV('idx_d16value1', false);
                    QV('idx_d16value2', true);
                }
            }
        }

        function usb_ond16checkhash() {
            var hashtype = Q('idx_d16valc1').value;
            var hashlen = hex2rstr(Q('idx_d16valc2').value).length;
            QE('idx_dlgOkButton', (Q('idx_d16valc3').value.length > 0) && ((hashtype == 1) && (hashlen == 20)) || ((hashtype == 2) && (hashlen == 32)) || ((hashtype == 3) && (hashlen == 48)));
        }

        var usb_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

        function usb_computeChecksum(s) {
            var A = 0;
            for (var i = 0; i < s.length; i++) A += s.charCodeAt(i);
            return usb_alphabet[A % 36];
        }

        function usb_generateRandomPid() {
            var pid = '';
            for (var i = 0; i < 7; i++) { pid += usb_alphabet[random(36)]; }
            return pid + usb_computeChecksum(pid);
        }

        function usb_generateRandomPps()
        {
            var pps = '', s;
            for (var j = 0; j < 8; j++) {
                s = '';
                for (var i = 0; i < 3; i++) s += usb_alphabet[random(36)];
                pps += s + usb_computeChecksum(s);
            }
            return pps;
        }

        // ###END###{USBSetup}

        // ###BEGIN###{SessionRecording}

        var recFile = null;
        var recFilePtr = 0;
        var recFileStartTime = 0;
        var recFileLastTime = 0;
        var recFileEndTime = 0;
        var recFileMetadata = null;
        var recFileProtocol = 0;
        var agentDesktop = null;
        var agentTerminal = null;
        var amtDesktop = null;
        var srec_playing = 0; // 0 = Stopped, 1 = Pausing, 2 = Playing
        var readState = 0;
        var waitTimer = null;
        var waitTimerArgs = null;
        var srec_deskAspectRatio = 0;
        var currentDeltaTimeTotalSec = 0;

        function readNextBlock(func) {
            if ((recFilePtr + 16) > recFile.size) { QS('srec_progressbar').width = '100%'; func(-1); } else {
                var fr = new FileReader();
                fr.onload = function () {
                    var type = ReadShort(this.result, 0);
                    var flags = ReadShort(this.result, 2);
                    var size = ReadInt(this.result, 4);
                    var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
                    if ((recFilePtr + 16 + size) > recFile.size) { QS('srec_progressbar').width = '100%'; func(-1); } else {
                        var fr2 = new FileReader();
                        fr2.onload = function () {
                            recFilePtr += (16 + size);
                            if (recFileEndTime == 0) {
                                // File pointer progress bar
                                QS('srec_progressbar').width = Math.floor(100 * (recFilePtr / recFile.size)) + '%';
                            } else {
                                // Time progress bar
                                QS('srec_progressbar').width = Math.floor(((recFileLastTime - recFileStartTime) / (recFileEndTime - recFileStartTime)) * 100) + '%';
                            }
                            func(type, flags, time, this.result);
                        };
                        fr2.readAsBinaryString(recFile.slice(recFilePtr + 16, recFilePtr + 16 + size));
                    }
                };
                fr.readAsBinaryString(recFile.slice(recFilePtr, recFilePtr + 16));
            }
        }

        function readLastBlock(func) {
            if (recFile.size < 32) { func(-1); } else {
                var fr = new FileReader();
                fr.onload = function () {
                    var type = ReadShort(this.result, 0);
                    var flags = ReadShort(this.result, 2);
                    var size = ReadInt(this.result, 4);
                    var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
                    if ((type == 3) && (size == 16) && (this.result.substring(16, 32) == 'MeshCentralMCREC')) { func(type, flags, time); } else { func(-1); }
                };
                fr.readAsBinaryString(recFile.slice(recFile.size - 32, recFile.size));
            }
        }

        function addInfo(name, value) { if (value == null) return ''; return addInfoNoEsc(name, EscapeHtml(value)); }

        function addInfoNoEsc(name, value) {
            if (value == null) return '';
            return '<span style=color:gray>' + EscapeHtml(name) + '</span>:&nbsp;<span style=font-size:20px;color:black>' + value + '</span><br/>';
        }

        function processFirstBlock(type, flags, time, data) {
            recFileProtocol = 0;
            if ((type != 1) || (flags != 0)) { cleanup(); return; }
            try { recFileMetadata = JSON.parse(data) } catch (ex) { cleanup(); return; }
            if ((recFileMetadata == null) || (recFileMetadata.magic != 'MeshCentralRelaySession') || (recFileMetadata.ver != 1)) { cleanup(); return; }
            var x = '';
            x += addInfo("Time", recFileMetadata.time);
            if (recFileEndTime != 0) {
                var secs = Math.floor((recFileEndTime - time) / 1000);
                if (secs > 1) { x += addInfo("Duration", format("{0} seconds", secs)); } else { x += addInfo("Duration", "1 second"); }
            }
            x += addInfo("Username", recFileMetadata.username);
            x += addInfo("UserID", recFileMetadata.userid);
            x += addInfo("SessionID", recFileMetadata.sessionid);
            if (recFileMetadata.ipaddr1 && recFileMetadata.ipaddr2) { x += addInfo("Addresses", format("{0} to {1}", recFileMetadata.ipaddr1, recFileMetadata.ipaddr2)); }
            x += addInfo("NodeID", recFileMetadata.nodeid);
            if (recFileMetadata.protocol) {
                var p = recFileMetadata.protocol;
                if (p == 1) { p = "MeshCentral Terminal"; }
                else if (p == 2) { p = "MeshCentral Desktop"; }
                else if (p == 100) { p = "Intel&reg; AMT WSMAN"; }
                else if (p == 101) { p = "Intel&reg; AMT Redirection"; }
                else if (p == 200) { p = "Intel&reg; AMT KVM"; }
                x += addInfoNoEsc("Protocol", p);
            }
            QV('srec_DeskParent', false);
            QV('srec_TermParent', false);
            if (recFileMetadata.protocol == 1) {
                // MeshCentral remote terminal
                recFileProtocol = 1;
                x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
                QE('srec_PlayButton', true);
                QE('srec_PauseButton', false);
                QE('srec_RestartButton', false);
                QV('srec_toggleviewmode', false);
                recFileStartTime = recFileLastTime = time;
            }
            else if (recFileMetadata.protocol == 2) {
                // MeshCentral remote desktop
                recFileProtocol = 2;
                x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
                QE('srec_PlayButton', true);
                QE('srec_PauseButton', false);
                QE('srec_RestartButton', false);
                QV('srec_toggleviewmode', true);
                recFileStartTime = recFileLastTime = time;
                agentDesktop = CreateAgentRemoteDesktop('srec_Desk');
                agentDesktop.onScreenSizeChange = srec_deskAdjust;
                agentDesktop.State = 3;
                srec_deskAdjust();
            }
            else if (recFileMetadata.protocol == 101) {
                // Intel AMT Redirection
                recFileProtocol = 101;
                x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
                QE('srec_PlayButton', true);
                QE('srec_PauseButton', false);
                QE('srec_RestartButton', false);
                QV('srec_toggleviewmode', true);
                recFileStartTime = recFileLastTime = time;
                amtDesktop = CreateAmtRemoteDesktop('srec_Desk');
                amtDesktop.onScreenSizeChange = srec_deskAdjust;
                amtDesktop.State = 3;
                amtDesktop.Start();
                srec_deskAdjust();
            } else if (recFileMetadata.protocol == 200) {
                // Intel AMT Midstream KVM
                recFileProtocol = 200;
                x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
                QE('srec_PlayButton', true);
                QE('srec_PauseButton', false);
                QE('srec_RestartButton', false);
                QV('srec_toggleviewmode', true);
                recFileStartTime = recFileLastTime = time;
                amtDesktop = CreateAmtRemoteDesktop('srec_Desk');
                amtDesktop.onScreenSizeChange = srec_deskAdjust;
                amtDesktop.State = 3;
                amtDesktop.Start();
                if (recFileMetadata.bpp) { amtDesktop.bpp = recFileMetadata.bpp; }
                if (recFileMetadata.graymode) { amtDesktop.graymode = recFileMetadata.graymode; }
                if (recFileMetadata.lowcolor) { amtDesktop.lowcolor = recFileMetadata.lowcolor; }
                amtDesktop.state = 3;
                srec_deskAdjust();
            }
            QV('srec_metadatadiv', true);
            QH('srec_metadatadiv', x);
            QH('srec_deskstatus', recFile.name);
        }

        function processBlock(type, flags, time, data) {
            if (type < 0) { srec_pause(); return; }
            var waitTime = Math.round((time - recFileLastTime) * parseFloat(Q('srec_PlaySpeed').value));
            if (waitTime < 5) {
                processBlockEx(type, flags, time, data);
            } else {
                waitTimerArgs = [type, flags, time, data]
                waitTimer = setTimeout(function () { waitTimer = null; processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]); }, waitTime);
            }
        }

        function processBlockEx(type, flags, time, data) {
            if (srec_playing == 0) return;
            var flagBinary = (flags & 1) != 0, flagUser = (flags & 2) != 0;

            // Update the clock
            var deltaTimeTotalSec = Math.floor((time - recFileStartTime) / 1000);
            if (currentDeltaTimeTotalSec != deltaTimeTotalSec) {
                currentDeltaTimeTotalSec = deltaTimeTotalSec;
                var deltaTimeHours = Math.floor(deltaTimeTotalSec / 3600);
                deltaTimeTotalSec -= (deltaTimeHours * 3600)
                var deltaTimeMinutes = Math.floor(deltaTimeTotalSec / 60);
                deltaTimeTotalSec -= (deltaTimeHours * 60)
                var deltaTimeSeconds = Math.floor(deltaTimeTotalSec);
                QH('srec_timespan', pad2(deltaTimeHours) + ':' + pad2(deltaTimeMinutes) + ':' + pad2(deltaTimeSeconds))
            }

            if ((type == 2) && flagBinary && !flagUser) {
                // Device --> User data
                if (recFileProtocol == 1) {
                    // MeshCentral Terminal
                    agentTerminal.ProcessData(data);
                } else if (recFileProtocol == 2) {
                    // MeshCentral Remote Desktop
                    agentDesktop.ProcessData(data);
                } else if (recFileProtocol == 101) {
                    // Intel AMT KVM
                    if ((readState == 0) && (rstr2hex(data).startsWith('4100000000000000'))) {
                        // We are not authenticated, KVM data starts here.
                        readState = 1;
                        if (data.length > 8) {
                            var view = new Uint8Array(data.length - 8);
                            for (var i = 8; i < data.length; i++) { view[i] = data.charCodeAt(i); }
                            amtDesktop.ProcessBinaryData(view.buffer);
                        }
                    } else if (readState == 1) {
                        var view = new Uint8Array(data.length);
                        for (var i = 0; i < data.length; i++) { view[i] = data.charCodeAt(i); }
                        amtDesktop.ProcessBinaryData(view.buffer);
                    }
                } else if (recFileProtocol == 200) {
                    // Intel AMT midstream KVM
                    var view = new Uint8Array(data.length);
                    for (var i = 0; i < data.length; i++) { view[i] = data.charCodeAt(i); }
                    amtDesktop.ProcessBinaryData(view.buffer);
                }
            } else if ((type == 2) && flagBinary && flagUser) {
                // User --> Device data
                if (recFileProtocol == 101) {
                    // Intel AMT KVM
                    if (rstr2hex(data) == '0000000008080001000700070003050200000000') { console.log('RGB8'); amtDesktop.bpp = 1; } // Switch to 1 byte per pixel, 256 colors
                    if (rstr2hex(data) == '000000000808000100FF00000000000000000000') { console.log('GRAY8'); amtDesktop.bpp = 1; obj.graymode = true; } // Switch to 1 byte per pixel, 256 grays
                    if (rstr2hex(data) == '0000000008040001000F00000000000000000000') { console.log('GRAY4'); amtDesktop.bpp = 1; obj.graymode = true; obj.lowcolor = true; } // Switch to 1 byte per pixel, 16 grays
                }
            }

            // This is a PNG screenshot of the display, load it and render it.
            if ((type == 3) && (recFileProtocol == 200)) {
                var tile = new Image();
                tile.src = 'data:image/png;base64,' + btoa(data);
                tile.onload = function () { amtDesktop.canvas.drawImage(tile, 0, 0); }
                tile.error = function () { }
            }

            recFileLastTime = time;
            if (srec_playing == 2) { readNextBlock(processBlock); }
        }

        function srec_cleanup() {
            recFile = null;
            recFilePtr = 0;
            recFileMetadata = null;
            srec_playing = 0;
            if (agentDesktop != null) { agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height); agentDesktop = null; }
            if (amtDesktop != null) { amtDesktop.canvas.clearRect(0, 0, amtDesktop.canvasid.width, amtDesktop.canvasid.height); amtDesktop = null; }
            readState = 0;
            waitTimerArgs = null;
            currentDeltaTimeTotalSec = 0;
            recFileEndTime = 0;
            agentTerminal = null;
            if (waitTimer != null) { clearTimeout(waitTimer); waitTimer = null; }
            QH('srec_deskstatus', '');
            QE('srec_PlayButton', false);
            QE('srec_PauseButton', false);
            QE('srec_RestartButton', false);
            QS('srec_progressbar').width = '0px';
            QH('srec_timespan', '00:00:00');
            QV('srec_metadatadiv', true);
            QH('srec_metadatadiv', '<div style="width:100%;text-align:center;color:gray;margin-top:26px"><span style="font-size:20px">' + "Recorded Session Player" + '</span><div style="margin:4px">' + "Drag & drop a .mcrec file or click \"Open File...\"" + '</div></div>');
            QV('srec_DeskParent', false);
            QV('srec_TermParent', false);
            QV('srec_toggleviewmode', false);
        }

        function srec_ondrop(e) {
            haltEvent(e);

            // Check if these are files we can upload, remove all folders.
            if (e.dataTransfer == null) return;
            var files = [];
            for (var i in e.dataTransfer.files) {
                if ((e.dataTransfer.files[i].type != null) && (e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0) && (e.dataTransfer.files[i].name.endsWith('.mcrec'))) {
                    files.push(e.dataTransfer.files[i]);
                }
            }
            if (files.length == 0) return;
            srec_cleanup();
            recFile = files[0];
            recFilePtr = 0;
            readNextBlock(processFirstBlock);
            readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
            srec_restart();
        }

        function srec_openfile() {
            var x = '<input type=file name=files id=srec_p2fileinput style=width:100% accept=".mcrec" onchange="openfileChanged()" />';
            setDialogMode(11, "Open File...", 3, srec_openfileEx, x);
            QE('idx_dlgOkButton', false);
        }

        function srec_openfileEx() {
            var xfiles = Q('srec_p2fileinput').files;
            if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
            if (files.length == 0) return;
            srec_cleanup();
            recFile = files[0];
            recFilePtr = 0;
            readNextBlock(processFirstBlock);
            readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
            Q('srec_OpenFileButton').blur();
        }

        function openfileChanged() {
            var xfiles = Q('srec_p2fileinput').files;
            if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
            QE('idx_dlgOkButton', files.length == 1);
        }

        function srec_togglePause() {
            if (recFile != null) { if (srec_playing == 2) { srec_pause(); } else { if (recFilePtr != recFile.size) { srec_play(); } } } return false;
        }

        function srec_play() {
            Q('srec_PlayButton').blur();
            if ((srec_playing == 2) || (recFileProtocol == 0)) return;
            srec_playing = 2;
            QV('srec_metadatadiv', false);
            QE('srec_PlayButton', false);
            QE('srec_PauseButton', true);
            QE('srec_RestartButton', false);
            if ((recFileProtocol == 2) || (recFileProtocol == 101) || (recFileProtocol == 200)) {
                QV('srec_DeskParent', true);
                QV('srec_TermParent', false);
            } else if ((recFileProtocol == 1) && (agentTerminal == null)) {
                QV('srec_DeskParent', false);
                QV('srec_TermParent', true);
                agentTerminal = CreateAmtRemoteTerminal('srec_Term', {});
                agentTerminal.State = 3;
                agentTerminal.heightLock = 1;
            }
            readNextBlock(processBlock);
        }

        function srec_pause() {
            Q('srec_PauseButton').blur();
            if (srec_playing < 2) return;
            srec_playing = 1;
            QE('srec_PlayButton', recFilePtr != recFile.size);
            QE('srec_PauseButton', false);
            QE('srec_RestartButton', recFilePtr != 0);
            if (waitTimer != null) {
                clearTimeout(waitTimer);
                waitTimer = null;
                processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]);
                waitTimerArgs = null;
            }
        }

        function srec_restart() {
            Q('srec_RestartButton').blur();
            if (srec_playing == 0) return;
            recFilePtr = 0;
            readState = 0;
            currentDeltaTimeTotalSec = 0;
            QV('srec_metadatadiv', true);
            QE('srec_PlayButton', true);
            QE('srec_PauseButton', false);
            QE('srec_RestartButton', false);
            QS('srec_progressbar').width = '0px';
            QH('srec_timespan', '00:00:00');
            QV('srec_DeskParent', false);
            QV('srec_TermParent', false);
            if (agentDesktop) {
                agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
            }
            if (amtDesktop) {
                amtDesktop.canvas.clearRect(0, 0, amtDesktop.canvasid.width, amtDesktop.canvasid.height);
                amtDesktop = CreateAmtRemoteDesktop('srec_Desk');
                amtDesktop.onScreenSizeChange = srec_deskAdjust;
                amtDesktop.State = 3;
                amtDesktop.Start();
                if (recFileMetadata.protocol == 200) {
                    if (recFileMetadata.bpp) { amtDesktop.bpp = recFileMetadata.bpp; }
                    if (recFileMetadata.graymode) { amtDesktop.graymode = recFileMetadata.graymode; }
                    if (recFileMetadata.lowcolor) { amtDesktop.lowcolor = recFileMetadata.lowcolor; }
                    amtDesktop.state = 3;
                    srec_deskAdjust();
                }
            }
            if (agentTerminal) { agentTerminal = null; }
        }

        function clearConsoleMsg() {
            //QH('srec_p11DeskConsoleMsg', '');
        }

        // Toggle the web page to full screen
        function srec_toggleAspectRatio(toggle) {
            if (toggle === 1) { srec_deskAspectRatio = ((srec_deskAspectRatio + 1) % 3); }
            srec_deskAdjust();
        }

        function srec_deskAdjust() {
            var parentH = Q('srec_DeskParent').clientHeight, parentW = Q('srec_DeskParent').clientWidth;
            var deskH = Q('srec_Desk').height, deskW = Q('srec_Desk').width;
            QS('srec_Desk')['margin-top'] = null;
            QS('srec_Desk')['margin-left'] = null;

            if (srec_deskAspectRatio == 2) {
                // Scale mode
                QS('srec_Desk')['margin-top'] = null;
                QS('srec_Desk').height = '100%';
                QS('srec_Desk').width = '100%';
                QS('srec_DeskParent').overflow = 'hidden';
            } else if (srec_deskAspectRatio == 1) {
                // Zoomed mode
                QS('srec_Desk')['margin-top'] = '0px';
                QS('srec_Desk').height = deskH + 'px';
                QS('srec_Desk').width = deskW + 'px';
                QS('srec_DeskParent').overflow = 'scroll';
            } else {
                // Fixed aspect ratio
                if ((parentH / parentW) > (deskH / deskW)) {
                    var hNew = ((deskH * parentW) / deskW) + 'px';
                    QS('srec_Desk').height = hNew;
                    QS('srec_Desk').width = '100%';
                    QS('srec_Desk')['margin-top'] = ((parentH - ((deskH * parentW) / deskW)) / 2) + 'px';
                } else {
                    var wNew = ((deskW * parentH) / deskH) + 'px';
                    QS('srec_Desk').height = '100%';
                    QS('srec_Desk').width = wNew;
                    QS('srec_Desk')['margin-left'] = ((parentW - ((deskW * parentH) / deskH)) / 2) + 'px'
                }
                QS('srec_DeskParent').overflow = 'hidden';
            }
        }

        function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }

        // ###END###{SessionRecording}

        //
        // POPUP DIALOG
        //

        // undefined = Hidden, 1 = Generic Message
        var xxdialogMode;
        var xxdialogFunc;
        var xxdialogButtons;
        var xxdialogTag;

        // Display a dialog box
        // Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 11 only)
        function setDialogMode(x, y, b, f, c, tag) {
            xxdialogMode = x;
            xxdialogFunc = f;
            xxdialogButtons = b;
            xxdialogTag = tag;
            QE('idx_dlgOkButton', true);
            QV('idx_dlgOkButton', b & 1);
            QV('idx_dlgCancelButton', b & 2);
            QV('id_dialogclose', b & 2);
            QV('idx_dlgDeleteButton', b & 4);
            if (y) QH('id_dialogtitle', y);
            for (var i = 1; i < 28; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
            QV('dialog', x);
            if (c) { if (x == 11) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }

            // ###BEGIN###{IDERStats}
            if (xxdialogMode != 0) { iderToggleDiskMap(false); }
            // ###END###{IDERStats}
        }

        function dialogclose(x) {
            var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
            setDialogMode();
            if (((b & 8) || x) && f) f(x, t);
        }

        function center() {
            QS('dialog').left = ((((getDocWidth() - 400) / 2)) + 'px');
            // ###BEGIN###{Desktop}
            var sh = 0, mh = (Q('id_mainarea').offsetHeight - ((fullscreen == false)?126:53));
            // ###BEGIN###{Scripting}
            if (QS('id_scriptstatus').display == '') sh += 32; // If script status is displayed, reduce max-height by 22 pixels
            // ###END###{Scripting}
            // ###BEGIN###{IDER}
            if (QS('id_iderstatus').display == '') sh += 32; // If ider status is displayed, reduce max-height by 22 pixels
            // ###END###{IDER}
            QS('id_mainarea_pad').height = (Q('id_mainarea').offsetHeight - sh - ((fullscreen == false)?16:0)) + 'px';
            QS('Desk')['max-height'] =  (mh - sh) + 'px';
            QS('Desk')['max-width'] = (Q('id_mainarea').offsetWidth - ((fullscreen == false)?32:0)) + 'px';
            if (Q('id_DeskParent').offsetWidth != 0) { QS('Desk')['max-width'] = Q('id_DeskParent').offsetWidth; }
            if (fullscreen) {
                QS('id_mainarea_pad')['overflow-y'] = 'hidden';
                var h = (mh - sh - Q('Desk').offsetHeight) / 2;
                QS('Desk')['margin-top'] = h + 'px';
                QS('Desk')['margin-bottom'] = h + 'px';
            } else {
                QS('id_mainarea_pad')['overflow-y'] = 'scroll';
                QS('Desk')['margin-top'] = '0';
                QS('Desk')['margin-bottom'] = '0';
            }
            // ###END###{Desktop}
            // ###BEGIN###{Storage}
            //QS('id_mainarea_frame').height = Q('id_mainarea').offsetHeight;
            // ###END###{Storage}

            // ###BEGIN###{SessionRecording}
            srec_deskAdjust();
            // ###END###{SessionRecording}
        }
        function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
        function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }

        //
        // GENERIC METHODS
        //

        // ###BEGIN###{FileSaver}
        function SaveJsonFile(name, name2, desc, data) {
            var n = '', r = {}, d = new Date();
            if (amtsysstate) {
                n = '-' + amtsysstate['AMT_GeneralSettings'].response['HostName'];
                r = {'webappversion':version,'description':desc,'hostname':amtsysstate['AMT_GeneralSettings'].response['HostName'],'localtime':Date(),'utctime':new Date().toUTCString(),'isotime':new Date().toISOString()};
                if (HardwareInventory) r['systemid'] = guidToStr(HardwareInventory['CIM_ComputerSystemPackage'].response['PlatformGUID'].toLowerCase());
            }
            n += '-' + d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2) + '-' + ('0' + d.getHours()).slice(-2) + '-' + ('0' + d.getMinutes()).slice(-2);;
            r[name2] = data;
            // ###BEGIN###{!Mode-NodeWebkit}
            saveAs(data2blob(JSON.stringify(r, null, '  ').replace(/\n/g, '\r\n')), name + n + '.json');
            // ###END###{!Mode-NodeWebkit}
            // ###BEGIN###{Mode-NodeWebkit}
            var chooser = document.createElement('input');
            chooser.setAttribute('type', 'file')
            chooser.setAttribute('nwsaveas', name + n + '.json');
            chooser.addEventListener('change', function () { require('fs').writeFile(this.value, JSON.stringify(r, null, '  ').replace(/\n/g, '\r\n'), function () { }); }, false);
            chooser.click();
            // ###END###{Mode-NodeWebkit}
        }
        // ###END###{FileSaver}

        var httpErrorTable = {
            200: "OK",
            401: "Authentication Error",
            408: "Timeout Error",
            601: "WSMAN Parsing Error",
            602: "Unable to parse HTTP response header",
            603: "Unexpected HTTP enum response",
            604: "Unexpected HTTP pull response",
            // ###BEGIN###{Mode-NodeWebkit}
            998: "Invalid TLS certificate",
            // ###END###{Mode-NodeWebkit}
            997: "Invalid Digest Realm"
        }
        function errcheck(s, stack) {
            if (wsstack == null || amtstack != stack) return true;
            if (s != 200 && s != 9) {
                setDialogMode();
                wsstack.comm.FailAllError = 999; // Cause all new responses to be silent
                amtstack.CancelAllQueries(999);
                QH('id_messageviewstr', ((httpErrorTable[s])?(httpErrorTable[s]):(format("Error #{0}", s))));
                // ###BEGIN###{Mode-MeshCentral2}
                if (s == 401) { QH('id_messageviewstr', "Authentication Error" + '<br /><br /><input type=button value=\"' + "Set new credentials" + '\" onclick=meshcentral2credCallback(true)></input>'); }
                // ###END###{Mode-MeshCentral2}
                go(100);
                QS('id_progressbar').width = 0;
                // ###BEGIN###{ComputerSelector}
                Q('id_messageviewbutton').focus();
                // ###END###{ComputerSelector}

                // ###BEGIN###{Mode-NodeWebkit}
                if (s == 998) {
                    //console.log('errcheck', wsstack.comm.xtlsCertificate.fingerprint);
                    if (wsstack.comm.xtlsCertificate != null) {
                        showTlsCert(11, '<img style=float:left;margin-right:8px src=warning.png width=48 height=48><div style=min-height:48px;display:table><div style=display:table-cell;vertical-align:middle>' + "Intel&reg; AMT connected with the following certificate. Press cancel to disconnect if this is not the expected certificate." + '</div></div>', wsstack.comm.xtlsCertificate, 1);
                    }
                }
                // ###END###{Mode-NodeWebkit}
            }
            return (s != 200);
        }

        // ###BEGIN###{Storage}
        function goiFrame(e,x,y) {
            if (xxdialogMode) return;
            go(x);
            // ###BEGIN###{Mode-NodeWebkit}
            var ports = portsFromHost(currentcomputer['host'], currentcomputer['tls']);
            y = (currentcomputer['tls']==0?'http://':'https://') + ports.host + ':' + ports.http + y;
            // ###END###{Mode-NodeWebkit}
            if ((e.shiftKey == true) || (Q('id_StorageIFrame').src.endsWith(y) == false)) Q('id_StorageIFrame').src = y;
            QV('id_mainarea_pad', false);
            QV('id_mainarea_frame', true);
        }
        // ###END###{Storage}

        function go(x, force) {
            if (xxdialogMode && force != 1) return;
            // ###BEGIN###{Mode-NodeWebkit}
            // Remove left bar selection
            var leftBarItems = ['LeftMenuMyDevices', 'LeftMenuMyCerts', 'LeftMenuMyUsb'];
            // ###BEGIN###{SessionRecording}
            leftBarItems.push('LeftMenuPlayer');
            // ###END###{SessionRecording}
            for (var i in leftBarItems) { Q(leftBarItems[i]).classList.remove('lbbuttonsel'); Q(leftBarItems[i]).classList.remove('lbbuttonsel2'); }
            if (x == 101) { Q('LeftMenuMyDevices').classList.add('lbbuttonsel2'); }
            if (x == 103) { Q('LeftMenuMyCerts').classList.add('lbbuttonsel2'); }
            if (x == 102) { Q('LeftMenuMyUsb').classList.add('lbbuttonsel2'); }
            if (x == 104) { Q('LeftMenuPlayer').classList.add('lbbuttonsel2'); }
            QV('LeftSideToolBar', ((x >= 101) && (x <= 104)));
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{Storage}
            QV('id_mainarea_frame', false);
            QV('id_mainarea_pad', true);
            // ###END###{Storage}
            // ###BEGIN###{ComputerSelector}
            QV('id_computerSelector', x == 101);
            // ###END###{ComputerSelector}
            // ###BEGIN###{Mode-LMS}
            QV('id_lmsMainPanel', x == 101);
            // ###END###{Mode-LMS}
            // ###BEGIN###{USBSetup}
            QV('id_usbSetupPanel', x == 102);
            // ###END###{USBSetup}
            // ###BEGIN###{CertificateManager}
            QV('id_certManagerPanel', x == 103);
            // ###END###{CertificateManager}
            // ###BEGIN###{SessionRecording}
            QV('id_sessionPlayerPanel', x == 104);
            // ###END###{SessionRecording}
            QV('id_messageview', x == 100);
            QV('id_mainview', x < 100);
            for (var i = 0; i < 80; i++) { // Edit this line when adding a new screen
                QV('p' + i, i == x);
                var q = QS('go' + i);
                // ###BEGIN###{Look-Intel}
                if (q) { q['background-color'] = ((i == x)?'#abcae1':''); } // #e8eefe
                // ###END###{Look-Intel}
                // ###BEGIN###{Look-ISDU}
                if (q) { q['background-color'] = ((i == x)?'#abcae1':''); } // #e8eefe
                // ###END###{Look-ISDU}
                // ###BEGIN###{Look-BrandedCommander}
                if (q) { q['background-color'] = ((i == x)?'#abcae1':''); } // #e8eefe
                // ###END###{Look-BrandedCommander}
                // ###BEGIN###{Look-Unite}
                if (q) { q['background-color'] = ((i == x)?'#abcae1':''); } // #e8eefe
                // ###END###{Look-Unite}
                // ###BEGIN###{Look-Commander}
                if (q) { q['background-color'] = ((i == x)?'gray':''); }
                // ###END###{Look-Commander}
                // ###BEGIN###{Look-MeshCentral}
                if (q) { q['background-color'] = ((i == x)?'gray':''); }
                // ###END###{Look-MeshCentral}
            }
            currentView = x;
            // ###BEGIN###{Look-ISDU}
            QV('id_isdu-image1', x == 11);
            QV('id_isdu-image2', x == 8);
            QV('id_isdu-image3', x == 14 || x == 13);
            QV('id_isdu-image4', x == 1 || x == 0);
            QV('id_isdu-image5', x == 6 || x == 15);
            QV('id_isdu-image6', x == 18 || x == 19);
            QV('id_isdu-image7', x == 16 || x == 12 || x == 2);
            QV('id_isdu-image8', x == 17);
            // ###END###{Look-ISDU}
            // ###BEGIN###{Look-BrandedCommander}
            // ###BEGIN###{!Mode-Firmware}
            QV('id_isdu-image1', x == 11);
            QV('id_isdu-image2', x == 8);
            QV('id_isdu-image3', x == 14 || x == 13);
            QV('id_isdu-image4', x == 1 || x == 0);
            QV('id_isdu-image5', x == 6 || x == 15);
            QV('id_isdu-image6', x == 18 || x == 19);
            QV('id_isdu-image7', x == 16 || x == 12 || x == 2);
            QV('id_isdu-image8', x == 17);
            // ###END###{!Mode-Firmware}
            // ###END###{Look-BrandedCommander}
            // ###BEGIN###{Mode-NodeWebkit}
            NW_SetupMainMenu(x);
            // ###END###{Mode-NodeWebkit}
            // ###BEGIN###{Desktop}
            center();
            // ###END###{Desktop}
        }

        function portsFromHost(host, tls) {
            host = decodeURIComponent(host);
            var x = host.split(':'), hp = ((tls == 0) ? 16992 : 16993), rp = ((tls == 0) ? 16994 : 16995);
            if (x[0].indexOf('[') == 0) { // IPv6 address
                x = host.split(']:');
                if (x.length == 1) { return { host: host.substring(1, host.length - 1), http: hp, redir: rp } }
                if (x.length > 1) { var y = x[1].split(':'); if (y.length > 0) { hp = parseInt(y[0]); } if (y.length > 1) { rp = parseInt(y[1]); } }
                return { host: x[0].substring(1), http: hp, redir: rp }
            }
            if (x.length > 1) { hp = parseInt(x[1]); }
            if (x.length > 2) { rp = parseInt(x[2]); }
            return { host: x[0], http: hp, redir: rp }
        }
        function addLink(x, f) { return '<a style=cursor:pointer;color:blue onclick=\'' + f + '\'>&diams; ' + x + '</a>'; }
        function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
        function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
        function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
        function addDisabledOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; option.disabled = 1; Q(q).add(option); }
        function passwordcheck(p) { if (p.length < 8) return false; var upper = 0, lower = 0, number = 0, nonalpha = 0; for (var i in p) { var c = p.charCodeAt(i); if ((c > 64) && (c < 91)) { upper = 1; } else if ((c > 96) && (c < 123)) { lower = 1; } else if ((c > 47) && (c < 58)) { number = 1; } else { nonalpha = 1; } } return ((upper + lower + number + nonalpha) == 4); }
        function methodcheck(r) { if (r && r != null && r.Body && r.Body['ReturnValue'] != 0) { messagebox("Call Error", r.Header['Method'] + ': ' + (r.Body.ReturnValueStr + '').replace('_', ' ')); return true; } return false; }
        function TableStart() { return '<table class=\'log1 us\' cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>'; }
        function TableStart2() { return '<table class=\'log1 us\' cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>'; }
        function TableEntry(n, v) { return '<tr><td class=r1><p>' + n + '<td class=r1>' + v; }
        function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
        function TableEnd(n) { return '<tr><td colspan=2><p>' + (n?n:'') + '</table>'; }
        function AddButton(v, f) { return '<input type=button value=\'' + v + '\' onclick=\'' + f + '\' style=margin:4px>'; }
        function AddButton2(v, f, s) { return '<input type=button value=\'' + v + '\' onclick=\'' + f + '\' ' + s + '>'; }
        function AddRefreshButton(f) { return '<input type=button name=refreshbtn value="' + "Refresh" + '" onclick=\'refreshButtons(false);' + f + '\' style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
        function MoreStart() { return '<a style=cursor:pointer;color:blue id=morexxx1 onclick=QV(\"morexxx1\",false);QV(\"morexxx2\",true)>&#x25BC; ' + "More" + '</a><div id=morexxx2 style=display:none><br><hr>'; };
        function MoreEnd() { return '<a style=cursor:pointer;color:blue onclick=QV(\"morexxx2\",false);QV(\"morexxx1\",true)>&#x25B2; ' + "Less" + '</a></div>'; };
        function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
        function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
        function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
        function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + '-' + g.substring(10, 12) + g.substring(8, 10) + '-' + g.substring(14, 16) + g.substring(12, 14) + '-' + g.substring(16, 20) + '-' + g.substring(20); }
        function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
        function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
        function getDocHeight() { if (window.innerHeight) return window.innerHeight; if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientHeight != 0) return document.documentElement.clientHeight; return document.getElementsByTagName('body')[0].clientHeight; }
        function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px;overflow:hidden><b title="' + v + '">' + v + '</b></div><div>' + t + '</div></div>'; }
        function addHtmlValueNoTitle(t, v) { return '<div style=height:20px><div style=float:right;width:220px;overflow:hidden>' + v + '</b></div><div>' + t + '</div></div>'; }
        function numbersOnly(e, x) { return (event.charCode == 0) || (event.charCode == x) || (event.charCode >= 48 && event.charCode <= 57); }
        function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };

// ###BEGIN###{**ClosureAdvancedMode}
        // Google closure advanced mode externs
        window['cleanup'] = cleanup;
        window['disconnect'] = disconnect;
        window['dialogclose'] = dialogclose;
        window['go'] = go;
        window['QV'] = QV;
        window['numbersOnly'] = numbersOnly;
        window['syncClock'] = syncClock;
        window['showLinkPolicyDlg'] = showLinkPolicyDlg;
        // ###BEGIN###{PowerControl}
        window['showPowerActionDlg'] = showPowerActionDlg;
        // ###BEGIN###{PowerControl-Advanced}
        window['showAdvPowerDlg'] = showAdvPowerDlg;
        window['showAdvPowerDlgChange'] = showAdvPowerDlgChange;
        // ###END###{PowerControl-Advanced}
        // ###END###{PowerControl}
        window['showFeaturesDlg'] = showFeaturesDlg;
        window['showConsentDlg'] = showConsentDlg;
        // ###BEGIN###{NetworkSettings}
        window['showPingActionDlg'] = showPingActionDlg;
        window['showIPSetupDlg'] = showIPSetupDlg;
        window['updateIPSetupDlg'] = updateIPSetupDlg;
        window['showIPv6StateDlg'] = showIPv6StateDlg;
        window['showIPv6AddrDlg'] = showIPv6AddrDlg;
        // ###END###{NetworkSettings}
        window['PullSystemStatus'] = PullSystemStatus;
        window['changeAccountButton'] = changeAccountButton;
        window['changeAccountStateButton'] = changeAccountStateButton;
        window['newAccountButton'] = newAccountButton;
        window['showUserDetails'] = showUserDetails;
        window['showEditDnsDlg'] = showEditDnsDlg;
        window['showEditDnsDlgChange'] = showEditDnsDlgChange;
        window['setDialogMode'] = setDialogMode;
        window['PullUserInfo'] = PullUserInfo;
        window['toggleAccountButton'] = toggleAccountButton;
        window['showEditNameDlg'] = showEditNameDlg;
        window['updateAccountDialog'] = updateAccountDialog;
        window['refreshButtons'] = refreshButtons;
        window['showPowerPolicyDlg'] = showPowerPolicyDlg;
        // ###BEGIN###{HardwareInfo}
        window['PullHardware'] = PullHardware;
        // ###BEGIN###{FileSaver}
        window['SaveHardwareLog'] = SaveHardwareLog;
        // ###END###{FileSaver}
        // ###END###{HardwareInfo}
        // ###BEGIN###{WsmanBrowser}
        // ###BEGIN###{FileSaver}
        window['saveEntireAmtState'] = saveEntireAmtState;
        // ###END###{FileSaver}
        // ###END###{WsmanBrowser}
        // ###BEGIN###{ContextMenus}
        window['handleContextMenu'] = handleContextMenu;
        window['hideContextMenu'] = hideContextMenu;
        // ###END###{ContextMenus}
        // ###BEGIN###{Mode-NodeWebkit}
        window['showTlsCert'] = showTlsCert;
        window['downloadTlsCert'] = downloadTlsCert;
        // ###END###{Mode-NodeWebkit}

        // ###BEGIN###{Desktop}
        window['connectDesktopButton'] = connectDesktopButton;
        window['connectDesktop'] = connectDesktop;
        window['deskToggleFull'] = deskToggleFull;
        window['showDesktopSettings'] = showDesktopSettings;
        window['dmousedown'] = dmousedown;
        window['dmouseup'] = dmouseup;
        window['dmousemove'] = dmousemove;
        window['drotate'] = drotate;
        window['sendCAD'] = sendCAD;
        // ###BEGIN###{FileSaver}
        window['deskSaveImage'] = deskSaveImage;
        // ###END###{FileSaver}
        // ###BEGIN###{DesktopFocus}
        window['deskToggleFocus'] = deskToggleFocus;
        // ###END###{DesktopFocus}
        // ###BEGIN###{Desktop-Multi}
        window['desktopSwitchScreen'] = desktopSwitchScreen;
        // ###END###{Desktop-Multi}
        // ###END###{Desktop}

        // ###BEGIN###{Desktop-Settings}
        window['showDesktopSettingsDlg'] = showDesktopSettingsDlg;
        window['showDesktopSettingsDlgUpdate'] = showDesktopSettingsDlgUpdate;
        // ###END###{Desktop-Settings}

        // ###BEGIN###{Terminal}
        window['connectTerminal'] = connectTerminal;
        window['termPaste'] = termPaste;
        window['termSendKey'] = termSendKey;
        // ###BEGIN###{FileSaver}
        window['terminalCaptureToggle'] = terminalCaptureToggle;
        // ###END###{FileSaver}
        // ###BEGIN###{TerminalSize}
        window['termToggleSize'] = termToggleSize;
        // ###END###{TerminalSize}
        window['termToggleFx'] = termToggleFx;
        // ###BEGIN###{Terminal-Enumation-All}
        window['termToggleType'] = termToggleType;
        // ###END###{Terminal-Enumation-All}
        window['termPaste'] = termPaste;
        // ###END###{Terminal}

        // ###BEGIN###{IDER}
        window['iderStart'] = iderStart;
        window['iderStop'] = iderStop;
        // ###BEGIN###{IDERStats}
        window['iderToggleDiskMap'] = iderToggleDiskMap;
        // ###END###{IDERStats}
        // ###END###{IDER}

        // ###BEGIN###{RemoteAccess}
        window['editEnvironmentDetection'] = editEnvironmentDetection;
        window['editEnvironmentDetectionAdd'] = editEnvironmentDetectionAdd;
        window['editUserInitiatedCira'] = editUserInitiatedCira;
        window['editMpsPolicy'] = editMpsPolicy;
        window['showServerDetails'] = showServerDetails;
        window['AddRemoteAccessServer'] = AddRemoteAccessServer;
        window['AddRemoteAccessServerUpdate'] = AddRemoteAccessServerUpdate;
        window['edInputChg'] = edInputChg;
        window['editMpsPolicyUpdate'] = editMpsPolicyUpdate;
        window['editEnvironmentDetectionRemove'] = editEnvironmentDetectionRemove;
        // ###END###{RemoteAccess}

        // ###BEGIN###{EventLog}
        window['showEventDetails'] = showEventDetails;
        window['PullEventLog'] = PullEventLog;
        window['FreezeLog'] = FreezeLog;
        window['ClearLog'] = ClearLog;
        window['eventFilter'] = eventFilter;
        // ###BEGIN###{FileSaver}
        window['SaveEventLog'] = SaveEventLog;
        // ###END###{FileSaver}
        // ###END###{EventLog}

        // ###BEGIN###{AuditLog}
        window['PullAuditLog'] = PullAuditLog;
        window['auditFilter'] = auditFilter;
        window['showAuditDetails'] = showAuditDetails;
        // ###BEGIN###{FileSaver}
        window['SaveAuditLog'] = SaveAuditLog;
        // ###END###{FileSaver}
        // ###END###{AuditLog}

        // ###BEGIN###{Certificates}
        window['PullCertificates'] = PullCertificates;
        window['showCertDetails'] = showCertDetails;
        window['addCertButton'] = addCertButton;
        window['issueCertButton'] = issueCertButton;
        window['showSetTlsSecurityDlg'] = showSetTlsSecurityDlg;
        window['showSetTlsSecurityDlgUpdate'] = showSetTlsSecurityDlgUpdate;
        window['showKeyPairDetails'] = showKeyPairDetails;
        window['addCertButtonUpdate'] = addCertButtonUpdate;
        window['issueCertButtonUpdate'] = issueCertButtonUpdate;
        // ###BEGIN###{FileSaver}
        window['downloadCert'] = downloadCert;
        // ###END###{FileSaver}
        // ###END###{Certificates}

        // ###BEGIN###{AgentPresence}
        window['addWatchdogAction'] = addWatchdogAction;
        window['deleteWatchdogActions'] = deleteWatchdogActions;
        window['PullWatchdog'] = PullWatchdog;
        window['AddWatchdog'] = AddWatchdog;
        window['AddWatchdogUpdate'] = AddWatchdogUpdate;
        window['addWatchdogActionUpdate'] = addWatchdogActionUpdate;
        window['showWatchdogDetails'] = showWatchdogDetails;
        window['GenerateWatchdogGuid'] = GenerateWatchdogGuid;
        // ###END###{AgentPresence}

        // ###BEGIN###{SystemDefense}
        window['changeDefaultPolicy'] = changeDefaultPolicy;
        window['AddDefenseFilter'] = AddDefenseFilter;
        window['AddDefenseFilterUpdate'] = AddDefenseFilterUpdate;
        window['showFilterDetails'] = showFilterDetails;
        window['AddDefensePolicy'] = AddDefensePolicy;
        window['addFilterButton'] = addFilterButton;
        window['removeFilterButton'] = removeFilterButton;
        window['AddDefensePolicyUpdate'] = AddDefensePolicyUpdate;
        window['showPolicyDetails'] = showPolicyDetails;
        window['deleteDefensePolicy'] = deleteDefensePolicy;
        // ###END###{SystemDefense}

        // ###BEGIN###{Wireless}
        window['showWifiStateDlg'] = showWifiStateDlg;
        window['showWifiDetails'] = showWifiDetails;
        window['wifiRemoveButton'] = wifiRemoveButton;
        window['showWifiNewProfile'] = showWifiNewProfile;
        window['updateWifiDialog'] = updateWifiDialog;
        window['wifiRefresh'] = wifiRefresh;
        // ###END###{Wireless}

        // ###BEGIN###{WsmanBrowser}
        window['wsmanQuery'] = wsmanQuery;
        window['wsmanFilter'] = wsmanFilter;
        window['QH'] = QH;
        window['QV'] = QV;
        // ###END###{WsmanBrowser}
        
        // ###BEGIN###{Alarms}
        window['PullAlarms'] = PullAlarms;
        window['RemoveAllAlarms'] = RemoveAllAlarms;
        window['showAddAlarm'] = showAddAlarm;
        window['showAlertDetails'] = showAlertDetails;
        window['alertDialogUpdate'] = alertDialogUpdate;
        // ###END###{Alarms}

        // ###BEGIN###{ComputerSelector}
        window['computerConnect'] = computerConnect;
        window['toolmenuclick'] = toolmenuclick;
        window['computerFilterFunc'] = computerFilterFunc;
        window['computerSelect'] = computerSelect;
        
        // ###BEGIN###{ComputerSelector-Local}
        window['updateComputerDialog'] = updateComputerDialog;
        window['computerEdit'] = computerEdit;
        window['addComputer'] = addComputer;
        window['newComputerList'] = newComputerList;
        window['openComputerList'] = openComputerList;
        window['saveComputerList'] = saveComputerList;
        // ###END###{ComputerSelector-Local}

        // ###BEGIN###{Scripting}
        window['computerStopScript'] = computerStopScript;
        window['mscript_runScriptDlg'] = mscript_runScriptDlg;
        window['onComputerChecked'] = onComputerChecked;
        window['mscript_showComputerScriptOutput'] = mscript_showComputerScriptOutput;
        // ###END###{Scripting}

        // ###BEGIN###{ComputerSelectorScanner}
        // ###BEGIN###{Mode-NodeWebkit}
        window['showScanDialog'] = showScanDialog;
        window['showScanDialogUpdate'] = showScanDialogUpdate;
        // ###END###{Mode-NodeWebkit}
        // ###END###{ComputerSelectorScanner}

        // ###END###{ComputerSelector}

        // ###BEGIN###{Mode-LMS}
        window['lmsRefresh'] = lmsRefresh;
        window['lmsConfigure'] = lmsConfigure;
        window['lmsLogin'] = lmsLogin;
        window['lmsConfigureLogin'] = lmsConfigureLogin;
        window['lmsUpdateLoginDialog'] = lmsUpdateLoginDialog;
        window['lmsShowVersionsDlg'] = lmsShowVersionsDlg;
        window['lmsActivate'] = lmsActivate;
        window['lmsDeactivate'] = lmsDeactivate;
        window['toolmenuclick'] = toolmenuclick;
        window['lmsShowTrustedHashesDlg'] = lmsShowTrustedHashesDlg;
        // ###END###{Mode-LMS}

        // ###BEGIN###{Storage}
        window['SetStorageName'] = SetStorageName;
        window['showStorageDetails'] = showStorageDetails;
        window['PullStorage'] = PullStorage;
        window['UploadToStorage'] = UploadToStorage;
        window['goiFrame'] = goiFrame;
        // ###BEGIN###{Mode-Firmware}
        window['OpenFromStorage'] = OpenFromStorage;
        // ###END###{Mode-Firmware}
        // ###BEGIN###{Mode-LMS}
        window['OpenFromStorage'] = OpenFromStorage;
        // ###END###{Mode-LMS}
        // ###BEGIN###{FileSaver}
        window['DownloadFromStorage'] = DownloadFromStorage;
        // ###END###{FileSaver}
        // ###BEGIN###{Mode-NodeWebkit}
        window['UploadAppToStorage'] = UploadAppToStorage;
        // ###END###{Mode-NodeWebkit}
        // ###END###{Storage}

        // ###BEGIN###{Scripting}
        window['script_runScriptDlg'] = script_runScriptDlg;
        window['script_Stop'] = script_Stop;
        // ###END###{Scripting}

        // ###BEGIN###{Scripting-Editor}
        // ###BEGIN###{FileSaver}
        window['script_saveScript'] = script_saveScript;
        // ###END###{FileSaver}
        window['resetScriptButton'] = resetScriptButton;
        window['runScriptButton'] = runScriptButton;
        window['breakScriptButton'] = breakScriptButton;
        window['stepScriptButton'] = stepScriptButton;
        window['scriptViewButton'] = scriptViewButton;
        window['script_fonfilterchanged'] = script_fonfilterchanged;
        window['script_fonclick'] = script_fonclick;
        window['script_fondragstart'] = script_fondragstart;
        window['script_fondragend'] = script_fondragend;
        window['script_fondragenter'] = script_fondragenter;
        window['script_fondragleave'] = script_fondragleave;
        window['script_fondrop'] = script_fondrop;
        window['script_foneditclick'] = script_foneditclick;
        window['script_foneditclickEx'] = script_foneditclickEx;
        // ###END###{Scripting-Editor}

        // ###BEGIN###{USBSetup}
        window['usb_newSetupBin'] = usb_newSetupBin;
        window['usb_openSetupBin'] = usb_openSetupBin;
        window['usb_addRecordSetupBin'] = usb_addRecordSetupBin;
        window['usb_addvariable'] = usb_addvariable;
        window['usb_editheader'] = usb_editheader;
        window['usb_editrecord'] = usb_editrecord;
        window['usb_editvariable'] = usb_editvariable;
        window['usb_ond16typechange'] = usb_ond16typechange;
        // ###BEGIN###{FileSaver}
        window['usb_saveSetupBin'] = usb_saveSetupBin;
        // ###END###{FileSaver}
        // ###END###{USBSetup}

        // ###BEGIN###{Mode-MeshCentral2}
        window['connectButtonfunction'] = connectButtonfunction;
        // ###END###{Mode-MeshCentral2}

// ###END###{**ClosureAdvancedMode}

        // Get things started
        startup();
    </script>
</body>
</html>
